Skip to content

Publish Capture v1.0.0 release asset with checksum-pinned download #20

Publish Capture v1.0.0 release asset with checksum-pinned download

Publish Capture v1.0.0 release asset with checksum-pinned download #20

Workflow file for this run

name: ci
on:
push:
pull_request:
workflow_dispatch:
permissions:
contents: read
jobs:
unit:
strategy:
fail-fast: false
matrix:
os: [windows-latest, ubuntu-latest]
python-version: ["3.11", "3.12"]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: ${{ matrix.python-version }}
- run: python -m pip install --no-deps .
- run: scriptorium --version
- run: scriptorium init --help
- run: scriptorium inventory --help
- run: scriptorium migrate --help
- run: scriptorium resume --help
- run: scriptorium status --help
- run: scriptorium doctor --help
- run: scriptorium host install --help
- run: scriptorium components --profile core --json
- run: scriptorium install core --target ./scriptorium-components-preview --json
- run: python -m unittest discover -s tests -v
- name: Run general project intake acceptance
run: python tests/e2e_general_intake.py
e2e-windows:
runs-on: windows-latest
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
path: scriptorium
persist-credentials: false
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
ref: v0.1.0
path: scriptorium-v0.1.0
persist-credentials: false
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
repository: scriptorium-suite/scriptorium-spec
ref: 36612e80c49f5a8f346a09ed73f4b1c67cef5135
path: scriptorium-spec
persist-credentials: false
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
repository: scriptorium-suite/steward
ref: 7aafad1b432207905072c769fe527a3d4d1b365e
path: steward
persist-credentials: false
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
repository: foxsplendid/Provenance
ref: 1e3f1c022148c33f257d8a27502b50dbe906611d
path: Provenance
persist-credentials: false
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
repository: foxsplendid/Academic-Slides-Agent
ref: 6371f1e6eac41f505aed39e58dafb689317cab65
path: Academic-Slides-Agent
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.12"
- name: Install pinned build backend
run: >-
python -m pip install
--disable-pip-version-check
--no-deps
--only-binary=:all:
"setuptools==83.0.0"
- name: Verify clean Windows install lifecycle
shell: pwsh
run: |
python .\scriptorium\tests\e2e_install_lifecycle.py `
--scriptorium-root .\scriptorium `
--spec-root .\scriptorium-spec `
--steward-root .\steward `
--provenance-root .\Provenance `
--previous-scriptorium-root .\scriptorium-v0.1.0 `
--require-windows `
--report .\install-lifecycle-report.json
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
$report = Get-Content -LiteralPath .\install-lifecycle-report.json -Raw | ConvertFrom-Json
if (
$report.status -ne "passed" -or
$report.lifecycle.clean_install -ne "passed" -or
$report.lifecycle.uninstall -ne "passed" -or
$report.lifecycle.reinstall -ne "passed" -or
$report.lifecycle.standalone_components -ne "passed" -or
$report.lifecycle.doctor_and_demo -ne "passed" -or
$report.lifecycle.version_transition.status -ne "passed" -or
$report.lifecycle.version_transition.previous_version -ne "0.1.0"
) {
throw "Clean Windows install lifecycle did not pass"
}
- name: Install uv for Lectern
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
with:
version: "0.11.16"
python-version: "3.12.3"
- name: Install source checkouts
shell: pwsh
run: |
python -m venv .demo-venv
.\.demo-venv\Scripts\python.exe -m pip install --no-deps .\scriptorium
.\.demo-venv\Scripts\python.exe -m pip install --no-deps .\steward
.\.demo-venv\Scripts\python.exe -m pip install --no-deps .\Provenance
- name: Install Lectern workspace without provider extras
run: uv sync --project .\Academic-Slides-Agent --all-packages --locked --no-dev
- name: Smoke installed public pull entries
shell: pwsh
run: |
& .\.demo-venv\Scripts\prov-sync-pull.exe --help | Out-Null
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& .\.demo-venv\Scripts\prov-sync-pending.exe --help | Out-Null
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& .\.demo-venv\Scripts\prov-sync-fill.exe --help | Out-Null
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& .\.demo-venv\Scripts\prov-sync-unresolved.exe --help | Out-Null
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& .\.demo-venv\Scripts\prov-ingest-research.exe --help | Out-Null
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
$contextVersion = & .\.demo-venv\Scripts\prov-context.exe --version
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
if (($contextVersion -join "`n").Trim() -ne '0.18.0') {
throw "Installed Provenance context runtime version mismatch"
}
$raw = & .\.demo-venv\Scripts\prov-sync-pull.exe --capabilities --json
$code = $LASTEXITCODE
if ($code -ne 0) { throw "Provenance capability probe exited $code" }
$capabilities = ($raw -join "`n") | ConvertFrom-Json
if ($capabilities.operation -ne "pull.capabilities") {
throw "Unexpected Provenance capability operation"
}
if ($capabilities.generated_by.name -ne "provenance") {
throw "Unexpected Provenance capability producer"
}
if ($capabilities.capabilities.pull_lock -ne $true) {
throw "Installed Provenance lacks pull-lock support"
}
& .\.demo-venv\Scripts\scriptorium.exe pull --help | Out-Null
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& .\.demo-venv\Scripts\scriptorium.exe inventory --help | Out-Null
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& .\.demo-venv\Scripts\scriptorium.exe migrate --help | Out-Null
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& .\.demo-venv\Scripts\scriptorium.exe status --help | Out-Null
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& .\.demo-venv\Scripts\scriptorium.exe resume --help | Out-Null
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
$errorRaw = & .\.demo-venv\Scripts\scriptorium.exe pull --json 2>$null
$errorCode = $LASTEXITCODE
if ($errorCode -ne 2) {
throw "Expected JSON usage error exit 2, received $errorCode"
}
$errorReport = ($errorRaw -join "`n") | ConvertFrom-Json
if (
$errorReport.operation -ne "pull" -or
$errorReport.status -ne "error" -or
$errorReport.exit_code -ne 2
) {
throw "JSON usage-error envelope changed"
}
$global:LASTEXITCODE = 0
- name: Smoke installed content-free inventory
shell: pwsh
run: |
$source = Join-Path $env:RUNNER_TEMP 'inventory source α'
$conversation = Join-Path $env:RUNNER_TEMP 'inventory conversations'
$zotero = Join-Path $env:RUNNER_TEMP 'inventory zotero'
New-Item -ItemType Directory -Path $source, $conversation, $zotero | Out-Null
[IO.File]::WriteAllText((Join-Path $source 'private-note.md'), 'PRIVATE_RESEARCH_SENTINEL')
[IO.File]::WriteAllText((Join-Path $source 'private-paper.pdf'), 'PRIVATE_PDF_SENTINEL')
[IO.File]::WriteAllText((Join-Path $conversation 'chat-history.zip'), 'PRIVATE_CHAT_SENTINEL')
[IO.File]::WriteAllText((Join-Path $zotero 'library.bib'), 'PRIVATE_ZOTERO_SENTINEL')
$raw = & .\.demo-venv\Scripts\scriptorium.exe inventory `
--source $source `
--conversation-export $conversation `
--zotero-export $zotero `
--json
$code = $LASTEXITCODE
if ($code -ne 0) { throw "Installed inventory exited $code" }
$serialized = $raw -join "`n"
$report = $serialized | ConvertFrom-Json
if (
$report.operation -ne 'inventory' -or
$report.status -ne 'planned' -or
$report.summary.candidates -ne 4
) {
throw "Installed inventory report changed"
}
foreach ($privateValue in @(
$source,
$conversation,
$zotero,
'private-note.md',
'private-paper.pdf',
'chat-history.zip',
'library.bib',
'PRIVATE_RESEARCH_SENTINEL'
)) {
if ($serialized.Contains($privateValue)) {
throw "Inventory report exposed a private source value"
}
}
if ([IO.File]::ReadAllText((Join-Path $source 'private-note.md')) -ne 'PRIVATE_RESEARCH_SENTINEL') {
throw "Inventory modified a source file"
}
- name: Smoke installed synthetic migration lifecycle
shell: pwsh
run: |
$root = Join-Path $env:RUNNER_TEMP 'migration smoke'
$source = Join-Path $root 'selected source'
$workspace = Join-Path $root 'research workspace'
$env:LOCALAPPDATA = Join-Path $root 'canonical local state'
New-Item -ItemType Directory -Path $source, $workspace | Out-Null
[IO.File]::WriteAllText(
(Join-Path $source 'synthetic-note.md'),
'# SYNTHETIC_MIGRATION_SENTINEL'
)
[IO.File]::WriteAllText(
(Join-Path $source 'synthetic-paper.pdf'),
'%PDF-1.4 SYNTHETIC'
)
$planRaw = & .\.demo-venv\Scripts\scriptorium.exe migrate plan `
--source $source `
--workspace $workspace `
--batch-id synthetic-ci `
--json
if ($LASTEXITCODE -ne 0) { throw "Installed migration plan failed" }
$planSerialized = $planRaw -join "`n"
$plan = $planSerialized | ConvertFrom-Json
if (
$plan.operation -ne 'plan' -or
$plan.status -ne 'planned' -or
$plan.summary.files -ne 2
) {
throw "Installed migration plan report changed"
}
if (Test-Path (Join-Path $workspace 'Sources')) {
throw "Migration plan wrote into the workspace"
}
if (Test-Path $env:LOCALAPPDATA) {
throw "Migration plan persisted private state"
}
$applyRaw = & .\.demo-venv\Scripts\scriptorium.exe migrate apply `
--source $source `
--workspace $workspace `
--batch-id synthetic-ci `
--json
if ($LASTEXITCODE -ne 0) { throw "Installed migration apply failed" }
$applySerialized = $applyRaw -join "`n"
$apply = $applySerialized | ConvertFrom-Json
if (
$apply.operation -ne 'apply' -or
$apply.status -ne 'applied' -or
$apply.summary.changed -ne 2
) {
throw "Installed migration apply report changed"
}
$verifyRaw = & .\.demo-venv\Scripts\scriptorium.exe migrate verify `
--workspace $workspace `
--batch-id synthetic-ci `
--json
if ($LASTEXITCODE -ne 0) { throw "Installed migration verify failed" }
$verify = ($verifyRaw -join "`n") | ConvertFrom-Json
if ($verify.operation -ne 'verify' -or $verify.status -ne 'applied') {
throw "Installed migration verify report changed"
}
$repeatRaw = & .\.demo-venv\Scripts\scriptorium.exe migrate apply `
--workspace $workspace `
--batch-id synthetic-ci `
--json
if ($LASTEXITCODE -ne 0) { throw "Installed migration reapply failed" }
$repeat = ($repeatRaw -join "`n") | ConvertFrom-Json
if ($repeat.status -ne 'unchanged') {
throw "Installed migration reapply was not idempotent"
}
$rollbackRaw = & .\.demo-venv\Scripts\scriptorium.exe migrate rollback `
--workspace $workspace `
--batch-id synthetic-ci `
--json
if ($LASTEXITCODE -ne 0) { throw "Installed migration rollback failed" }
$rollbackSerialized = $rollbackRaw -join "`n"
$rollback = $rollbackSerialized | ConvertFrom-Json
if (
$rollback.operation -ne 'rollback' -or
$rollback.status -ne 'rolled-back' -or
$rollback.summary.changed -ne 2
) {
throw "Installed migration rollback report changed"
}
$allReports = @(
$planSerialized,
$applySerialized,
($verifyRaw -join "`n"),
($repeatRaw -join "`n"),
$rollbackSerialized
) -join "`n"
foreach ($privateValue in @(
$root,
$source,
$workspace,
'synthetic-note.md',
'synthetic-paper.pdf',
'SYNTHETIC_MIGRATION_SENTINEL'
)) {
if ($allReports.Contains($privateValue)) {
throw "Migration report exposed a private source value"
}
}
if (
[IO.File]::ReadAllText((Join-Path $source 'synthetic-note.md')) -ne
'# SYNTHETIC_MIGRATION_SENTINEL'
) {
throw "Migration modified its source"
}
$remaining = @(
Get-ChildItem `
(Join-Path $workspace 'Sources\Imported\synthetic-ci') `
-File `
-Recurse `
-ErrorAction SilentlyContinue
)
if ($remaining.Count -ne 0) {
throw "Migration rollback left owned files"
}
- name: Run isolated public pull E2E
shell: pwsh
run: |
& .\.demo-venv\Scripts\python.exe `
.\scriptorium\tests\e2e_pull.py `
--provenance-root .\Provenance `
--spec-root .\scriptorium-spec
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
- name: Run offline Steward to Lectern golden path
shell: pwsh
run: |
& .\.demo-venv\Scripts\python.exe `
.\scriptorium\tests\e2e_slides.py `
--steward-root .\steward `
--spec-root .\scriptorium-spec `
--lectern-root .\Academic-Slides-Agent
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
- name: Run credential-free golden path
shell: pwsh
run: |
.\.demo-venv\Scripts\scriptorium.exe doctor `
--target demo `
--json `
--spec-root .\scriptorium-spec `
--steward-root .\steward `
--provenance-root .\Provenance > .\doctor-report.json
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
.\.demo-venv\Scripts\python.exe -c "import json, pathlib; report=json.loads(pathlib.Path(r'.\doctor-report.json').read_text(encoding='utf-8-sig')); assert report['status'] == 'ready'; assert report['readiness']['demo'] == 'ready'; assert report['readiness']['public_alpha'] == 'incomplete'; assert report['readiness']['literature'] in {'detected', 'file-only'}; assert report['readiness']['slides'] != 'ready'; assert report['checks'][0]['network']['os_egress'] == 'not-observed'"
.\.demo-venv\Scripts\scriptorium.exe demo `
--output '.\demo 输出' `
--spec-root .\scriptorium-spec `
--steward-root .\steward `
--provenance-root .\Provenance
.\.demo-venv\Scripts\python.exe -m json.tool '.\demo 输出\demo-report.json'
.\.demo-venv\Scripts\python.exe -c "import json, pathlib; report=json.loads(pathlib.Path(r'.\demo 输出\demo-report.json').read_text(encoding='utf-8')); assert report['demo_status'] == 'passed'"
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: scriptorium-demo-windows
path: |
demo 输出
doctor-report.json
install-lifecycle-report.json
retention-days: 14