Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/osv-scanner.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:
scanner_status="$?"
set -e
test -s artifacts/osv/osv-results.sarif
if [ "$scanner_status" -gt 1 ]; then
if [ "$scanner_status" -ne 0 ]; then
exit "$scanner_status"
fi

Expand All @@ -66,7 +66,7 @@ jobs:

upload-sarif:
name: osv / provider upload
if: ${{ github.event_name != 'pull_request' && (github.event.repository.private == false || vars.ENABLE_CODE_SCANNING_UPLOAD == 'true') }}
if: ${{ !cancelled() && needs.scan.result != 'skipped' && github.event_name != 'pull_request' && (github.event.repository.private == false || vars.ENABLE_CODE_SCANNING_UPLOAD == 'true') }}
needs: scan
runs-on: ubuntu-24.04
timeout-minutes: 10
Expand Down
70 changes: 22 additions & 48 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ jobs:
go run ./internal/tools/releasepreflight npm-existing \
--expected-json "$metadata" \
--actual-file /tmp/proofkit-candidate-view.json
lineage_state="existing_byte_match"
node - "$metadata" "$filename" "$report" <<'NODE'
const { execFileSync } = require("node:child_process");
const { writeFileSync } = require("node:fs");
Expand All @@ -132,17 +133,25 @@ jobs:
.sort((left, right) => left.path.localeCompare(right.path));
writeFileSync(report, `${JSON.stringify({ [metadata.name]: { ...metadata, files } }, null, 2)}\n`);
NODE
continue
fi
if ! grep -Eq 'E404|404 Not Found|Not found' /tmp/proofkit-candidate-view.err; then
cat /tmp/proofkit-candidate-view.err >&2
exit 1
else
if ! grep -Eq 'E404|404 Not Found|Not found' /tmp/proofkit-candidate-view.err; then
cat /tmp/proofkit-candidate-view.err >&2
exit 1
fi
npm publish "artifacts/package/${filename}" \
--dry-run \
--json \
--access public \
--registry="${REGISTRY_URL}" > "$report"
lineage_state="unpublished"
fi
npm publish "artifacts/package/${filename}" \
--dry-run \
--json \
--access public \
--registry="${REGISTRY_URL}" > "$report"
npm view "${package_name}@latest" name version --json --registry="${REGISTRY_URL}" > /tmp/proofkit-latest-view.json
go run ./internal/tools/releasepreflight npm-lineage \
--change-record-file release/change-record.v2.json \
--latest-file /tmp/proofkit-latest-view.json \
--expected-name "$package_name" \
--candidate-version "$package_version" \
--candidate-state "$lineage_state"
done < artifacts/publish/publish-order.txt
node <<'NODE'
const { readFileSync, readdirSync, writeFileSync } = require("node:fs");
Expand Down Expand Up @@ -382,9 +391,6 @@ jobs:
node <<'NODE'
const { readFileSync, readdirSync, writeFileSync } = require("node:fs");

const expectedRecords = require("./artifacts/package/npm-pack.json");
const publicationMode = readFileSync("artifacts/registry/npm-publication-mode.txt", "utf8").trim();
const expectedByName = new Map(expectedRecords.map((record) => [record.name, record]));
const files = readdirSync("artifacts/registry")
.filter((file) => file.startsWith("pack-") && file.endsWith(".json"))
.sort();
Expand All @@ -396,43 +402,9 @@ jobs:
return parsed[0];
});
records.sort((left, right) => left.name.localeCompare(right.name));
if (records.length !== expectedByName.size) {
throw new Error(`published registry package count mismatch: expected ${expectedByName.size}, got ${records.length}`);
}
const seen = new Set();
for (const record of records) {
const expected = expectedByName.get(record.name);
if (!expected) {
throw new Error(`unexpected published registry package ${record.name}`);
}
if (seen.has(record.name)) {
throw new Error(`duplicate published registry package ${record.name}`);
}
seen.add(record.name);
for (const field of ["version", "filename", "shasum", "integrity"]) {
if (record[field] !== expected[field]) {
throw new Error(`published registry ${record.name} ${field} mismatch: expected ${expected[field]}, got ${record[field]}`);
}
}
}
writeFileSync("artifacts/registry/npm-pack.json", `${JSON.stringify(records, null, 2)}\n`);
const summary = {
artifactKind: "proofkit.published-registry-artifact-set.v1",
publicationMode,
registry: "https://registry.npmjs.org",
source: publicationMode === "published_by_workflow"
? "post-publish npm pack from registry"
: "registry npm pack byte-match for preexisting version",
packages: records.map((record) => ({
name: record.name,
version: record.version,
filename: record.filename,
shasum: record.shasum,
integrity: record.integrity
}))
};
writeFileSync("artifacts/registry/published-registry-artifact-set.json", `${JSON.stringify(summary, null, 2)}\n`);
NODE
npm run npm:registry-evidence

- name: Verify root-only registry install and signatures
run: |
Expand Down Expand Up @@ -999,6 +971,7 @@ jobs:
--asset-names-file /tmp/proofkit-expected-release-assets.txt
cp /tmp/proofkit-release-view.json artifacts/release/github-release.json
go run ./internal/tools/releasepreflight retained-evidence --artifact-root artifacts
go run ./internal/tools/releasepreflight retained-evidence-verify --artifact-root artifacts
echo "release $GITHUB_REF_NAME already exists and matches the candidate artifacts" >&2
exit 0
fi
Expand All @@ -1014,6 +987,7 @@ jobs:
--notes-file artifacts/release/release-notes.md \
--asset-names-file /tmp/proofkit-expected-release-assets.txt
go run ./internal/tools/releasepreflight retained-evidence --artifact-root artifacts
go run ./internal/tools/releasepreflight retained-evidence-verify --artifact-root artifacts
final_dir="$(mktemp -d)"
for asset in "${expected_assets[@]}"; do
asset_name="$(basename "$asset")"
Expand Down
16 changes: 15 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,26 @@ own release, provider, or deployment evidence.
Use the narrowest owner-valid proof first, then the current closeout gate for
the imported surface.

For public contract-only changes:
For whitespace hygiene during iteration, check both unstaged and staged
changes against `HEAD`:

```bash
git diff --check
git diff --cached --check
```

For a committed public contract-only closeout, run the narrow owner-valid
contract gate and inspect the committed range rather than an empty worktree
diff:

```bash
git diff --check "$(git merge-base origin/main HEAD)"...HEAD
npm run command-contract:check
```

Neither whitespace command proves contract semantics; the owner-valid contract
or specification test remains mandatory.

For runtime, package, CLI, workflow, or specification changes:

```bash
Expand Down
7 changes: 7 additions & 0 deletions docs/proofkit-contract-map.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ owner boundaries. It is not a second command-family inventory.
| Receipts and producers | `proof-receipt-admission`, `receipt-producer-admission`, `receipt-currentness-scope`, `receipt-trust-class`, `producer-policy-self-proof` | receipt sets, producer policy, scope/currentness facts, trust classes | receipt shape, producer/receipt compatibility, self-proof diagnostics | producer authentication, freshness policy, CI trust roots | receipt/provenance report |
| Release and deployment | `release-authority`, `external-consumer`, `registry-consumer-proof-input-compose`, `registry-consumer`, `deployment-evidence-admission`, `completion-criteria`, `branch-authority`, `readiness-closeout` | package facts, tarball/registry facts, explicit primitive registry/install/smoke facts, deployment evidence, criteria, branch facts | artifact/channel boundary checks, registry-consumer input composition, release diagnostics, falsifiable criteria shape | package publication, registry fetch, package-manager execution, deployment, rollback, approval | composed input, release/deployment/readiness report |
| Supply-chain and quality | `self-check`, release workflow, `npm run release:sbom`, `npm run self:coverage`, `npm run go:actionlint`, `npm run go:bench` | release artifacts, source workflows, specs, bindings, witness plans, explicit benchmark invocation | deterministic self-check report shape, SBOM candidate evidence, coverage metrics, workflow lint routing, benchmark entrypoints | public-source provenance, vulnerability triage, license approval, CI run admission, release approval | self-check report, SBOM, metrics report, CI signal, or benchmark output |

The `npm run release:sbom`, `npm run self:coverage`, `npm run go:actionlint`,
and `npm run go:bench` routes above are maintainer commands for a source
checkout. They are not installed-package APIs because their implementations
depend on repository-only `internal/` or workflow sources. Installed consumers
must use the public `agentic-proofkit` CLI routes declared in
`proofkit/cli-contract.v2.json`.
| Repository structure | `repo-profile-admission`, `workspace-manifest-facts`, `workspace-registry`, `workspace-changed-package-plan`, `workspace-shard-partition`, `typescript-public-api-surfaces`, `text-policy`, `secret-scan`, `package-runtime-dependency-admission` | explicit repo/profile facts, caller-owned manifest records, caller-owned roots, caller-owned text file inventories, explicit TypeScript package-manifest and per-condition source paths, optional `environmentClassPolicies` tuples | structural admission, manifest-to-workspace fact projection, workspace graph projections, bounded TypeScript package public API checks over referenced files, text policy admission, explicit-inventory secret-like text detection, shard plans | repository freshness, git/file discovery, compiler output provenance, command policy, package manager truth, provider secret scanning | structural, fact, policy, or planning report |
| Custom and generated artifacts | `custom-rule-boundary`, `document-lifecycle-boundary`, `rendered-artifact-freshness`, `conformance-profile`, `json-report-cli-adapter-source`, `witness-plan`, `witness-scheduler-plan` | custom rule metadata, document lifecycle records, artifact digests, profile manifests, command metadata, adapter language | boundary checks, generated-view freshness shape, deterministic adapter source generation, scheduler metadata checks | rule execution, document meaning, cache contents, CI scheduling, committed generated-source freshness | boundary report, generated source artifact, or scheduler report |
| CLI metadata | `help` | optional command name or help flag | built-in command catalog and help text routing | command selection, semantic proof, freshness, merge policy | text help only |
Expand Down
30 changes: 27 additions & 3 deletions docs/release-process.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,20 @@ In a source checkout, the committed `release/change-record.v2.json` owns the
reviewed, version-bound declaration of the public-contract delta, migration
decision, platform requirements, known limitations, and rollback strategy. It
is not part of the installed npm or PyPI projection and does not infer change
completeness from the source diff. The repository-owned
completeness from the source diff.

Release-history migration support starts at the baseline named by the first
supporting release record. The exact baseline remains in that source-only,
immutable release evidence rather than this package-public document. The
repository does not backfill a machine release-history chain for earlier
pre-baseline development releases. Each later change record in its released
source commit owns exactly one edge from `previousVersion` to `version`. A
future cumulative migration plan may be derived only from a contiguous,
owner-admitted sequence of those immutable release records; it must not become
a second authored source of truth or infer migration semantics from a source
diff. No cumulative release-history planner is currently claimed.

The repository-owned
`release:manifest` tool admits that record and creates `release-manifest.json`,
`checksums.sha256`, `metadata-checksums.sha256`, `sbom-subjects.sha256`,
release notes, and deterministic SBOM candidate evidence from explicit package,
Expand Down Expand Up @@ -120,6 +133,13 @@ coverage metrics generation.
The dry-run package identity proves candidate tarball shape only. It does not
prove the bytes served by the registry after publish.

Candidate preflight also admits the npm registry `latest` identity. For an
unpublished candidate, `latest` must equal the change record
`previousVersion`. For an already-published candidate, exact candidate-to-
registry byte equality must be proven first and `latest` must equal the change
record `version`. This separates a new release edge from an idempotent replay
and rejects skipped or stale predecessor chains.

## Publish

Create and push an exact version tag:
Expand All @@ -134,7 +154,9 @@ The `release` workflow must:
1. verify source package identity;
2. run the package gate;
3. build publish candidate evidence through either npm publish dry-run or
exact existing-byte-match validation for an already published version;
exact existing-byte-match validation for an already published version, then
bind the branch-specific candidate state and admitted change record to the
exact npm `latest` package identity;
4. build Python wheel candidates for the same embedded Go CLI;
5. prove publish readiness before any registry side effect: the tag must equal
`v<package.json version>`, target a commit reachable from `main`, and have
Expand Down Expand Up @@ -168,7 +190,9 @@ The `release` workflow must:
`artifacts/retained-evidence-checksums.sha256`. The checksum manifest lives
at the retained artifact root and uses exact `release/...` and
`attestations/...` paths, so standard checksum verification executes against
the downloaded artifact layout without path rewriting. The release
the downloaded artifact layout without path rewriting. Each existing-release
and newly-created-release branch immediately runs the repository-owned
`retained-evidence-verify` preflight before reporting success. The release
manifest records GitHub Release channel data as candidate/archive inventory;
`github-release.json` owns post-create GitHub Release facts only inside
retained workflow evidence, not as a public release asset.
Expand Down
5 changes: 3 additions & 2 deletions docs/specs/proofkit-supply-chain-quality/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,9 @@ vulnerability absence, or consumer rollout safety by itself.
exact complete current breaking, addition, and migration inventories
including channel-specific generated continuation bytes, rejects missing,
substituted, reordered, or surplus entries, and owns one independently
authored byte-exact complete current release-note projection, while one
retained-
authored byte-exact complete current release-note projection. Candidate
preflight binds npm latest to `previousVersion` for an unpublished candidate
or to `version` only after exact existing-byte-match proof. One retained-
evidence owner builds and verifies checksums against exact
downloadable artifact-relative paths without inferring change completeness
from the source diff.
Expand Down
Loading
Loading