Portfolio Compliance Rollup
Aggregates a collection of per-repo Increment-4a attestations (.claude/attestations/<sha>.json)
into a single, integrity-hashed portfolio compliance report (Increment 4b). It answers the
CISO-mandate question the per-repo attestation cannot: is the whole portfolio compliant, on-version,
and uncorrupted? Each input attestation's sha256 integrity is verified before it is counted, a repo
with no attestation is recorded as a gap, and per-repo harness-version drift is computed.
When to use
- To roll up a directory of collected per-repo attestations into one portfolio verdict.
- With
--fetch to gather the latest attestation from each fleet repo via gh api first, then roll up.
- To
--verify <file> a stored rollup's own integrity checksum (corruption detection — the
checksum is stored inside the file it covers, so it is not proof of authenticity; that needs signing).
Do not use
- To generate a single repo's attestation — that is
/attestation (generate-attestation.js). This
skill only reads and aggregates 4a attestations; it never mutates them.
- To provision branch protection or deploy environments (
/provision, its protection/environments modes).
How it works
node .claude/scripts/portfolio-rollup.js <collection-dir> # roll up a local collection
node .claude/scripts/portfolio-rollup.js <collection-dir> --target-version 2.5.0
node .claude/scripts/portfolio-rollup.js <collection-dir> --fetch --fleet fleet.json
node .claude/scripts/portfolio-rollup.js --verify .claude/attestations/portfolio-rollup.json
- Collection dir vs
--fetch — the collection directory is the core, offline, deterministic mode:
it enumerates per-repo attestation files (a flat <owner>__<repo>.json set OR a per-repo subdir).
--fetch [--fleet fleet.json] first gathers each fleet repo's latest attestation via
gh api repos/{owner}/{repo}/contents/... (base64-decoded into the collection dir), then rolls up.
--fetch needs gh installed, authenticated, with org read access; owner/repo are segment-validated
before any gh path; a repo whose attestation is missing (404) is skipped and surfaces as not-attested;
gh absent/auth/permission exits 2 with a reason.
- Integrity is verified, not trusted — each input attestation is re-hashed (canonical
content-minus-integrity, sha256) and compared to its stored
integrity.hash. A tampered / failed /
wrong-algo attestation is integrity_ok:false, counted integrity_failed, and never counted
compliant. A missing attestation for a --fleet repo is a recorded not-attested compliance gap —
never silently omitted (no vacuous portfolio green).
- Version drift — each repo's
harness_version is compared (pure numeric major.minor.patch
semver) against --target-version, else the running harness version: current | behind | ahead |
unknown (a missing or non-semver version is unknown, never a silent current).
portfolio_compliant is fail-safe: true only when the portfolio is non-empty AND every repo is
compliant + integrity_ok + attested. Any non-compliant / not-evaluated / not-attested /
integrity_failed repo, or an empty portfolio, makes it false.
- The rollup is itself checksummed — the report carries its own
integrity:{algo:'sha256',hash} over
its canonical content-minus-integrity; --verify <file> recomputes and compares, exiting non-zero on
mismatch and never mutating the file.
Where the report lives
The rollup is written to --out (default .claude/attestations/portfolio-rollup.json). Like the 4a
attestation, this is a corruption-detecting checksummed artifact, not authenticity — anyone with
write access can rewrite the content and its hash, so a --verify PASS means "not accidentally
corrupted", not "genuine". Cryptographic authenticity / non-repudiation requires signing
(GPG/cosign/Sigstore) — the same documented seam as Increment 4a, not built here.
When authoring or editing this skill, follow docs/prompting-standards.md.
1---2name: portfolio-rollup3description: Aggregate per-repo compliance attestations into one integrity-hashed portfolio rollup — verifying each attestation's sha256 integrity, recording an unattested repo as a compliance gap, and computing harness-version drift across the fleet. Use over a local collection directory of attestations, or with --fetch to gather them via fleet.json + gh api. --verify re-checks a stored rollup's own integrity.4---56# Portfolio Compliance Rollup78Aggregates a collection of per-repo Increment-4a attestations (`.claude/attestations/<sha>.json`)9into a single, integrity-hashed portfolio compliance report (Increment 4b). It answers the10CISO-mandate question the per-repo attestation cannot: *is the whole portfolio compliant, on-version,11and uncorrupted?* Each input attestation's sha256 integrity is verified before it is counted, a repo12with no attestation is recorded as a gap, and per-repo harness-version drift is computed.1314## When to use1516- To roll up a directory of collected per-repo attestations into one portfolio verdict.17- With `--fetch` to gather the latest attestation from each fleet repo via `gh api` first, then roll up.18- To `--verify <file>` a stored rollup's own integrity checksum (corruption detection — the19 checksum is stored inside the file it covers, so it is not proof of authenticity; that needs signing).2021## Do not use2223- To generate a single repo's attestation — that is `/attestation` (`generate-attestation.js`). This24 skill only reads and aggregates 4a attestations; it never mutates them.25- To provision branch protection or deploy environments (`/provision`, its `protection`/`environments` modes).2627## How it works2829```30node .claude/scripts/portfolio-rollup.js <collection-dir> # roll up a local collection31node .claude/scripts/portfolio-rollup.js <collection-dir> --target-version 2.5.032node .claude/scripts/portfolio-rollup.js <collection-dir> --fetch --fleet fleet.json33node .claude/scripts/portfolio-rollup.js --verify .claude/attestations/portfolio-rollup.json34```3536- **Collection dir vs `--fetch`** — the collection directory is the core, offline, deterministic mode:37 it enumerates per-repo attestation files (a flat `<owner>__<repo>.json` set OR a per-repo subdir).38 `--fetch [--fleet fleet.json]` first gathers each fleet repo's latest attestation via39 `gh api repos/{owner}/{repo}/contents/...` (base64-decoded into the collection dir), then rolls up.40 `--fetch` needs `gh` installed, authenticated, with **org read** access; owner/repo are segment-validated41 before any gh path; a repo whose attestation is missing (404) is skipped and surfaces as `not-attested`;42 gh absent/auth/permission exits 2 with a reason.43- **Integrity is verified, not trusted** — each input attestation is re-hashed (canonical44 content-minus-integrity, sha256) and compared to its stored `integrity.hash`. A tampered / failed /45 wrong-algo attestation is `integrity_ok:false`, counted `integrity_failed`, and **never** counted46 compliant. A missing attestation for a `--fleet` repo is a recorded `not-attested` compliance gap —47 never silently omitted (no vacuous portfolio green).48- **Version drift** — each repo's `harness_version` is compared (pure numeric `major.minor.patch`49 semver) against `--target-version`, else the running harness version: `current` | `behind` | `ahead` |50 `unknown` (a missing or non-semver version is `unknown`, never a silent `current`).51- **`portfolio_compliant`** is fail-safe: `true` only when the portfolio is non-empty AND every repo is52 compliant + `integrity_ok` + attested. Any non-compliant / not-evaluated / not-attested /53 integrity_failed repo, or an empty portfolio, makes it `false`.54- **The rollup is itself checksummed** — the report carries its own `integrity:{algo:'sha256',hash}` over55 its canonical content-minus-integrity; `--verify <file>` recomputes and compares, exiting non-zero on56 mismatch and never mutating the file.5758## Where the report lives5960The rollup is written to `--out` (default `.claude/attestations/portfolio-rollup.json`). Like the 4a61attestation, this is a **corruption-detecting checksummed artifact, not authenticity** — anyone with62write access can rewrite the content and its hash, so a `--verify` PASS means "not accidentally63corrupted", not "genuine". Cryptographic authenticity / non-repudiation requires signing64(GPG/cosign/Sigstore) — the same documented seam as Increment 4a, not built here.6566When authoring or editing this skill, follow `docs/prompting-standards.md`.