fix: close immutable promotion trust gaps
This commit is contained in:
@@ -36,19 +36,26 @@ finding과 서명 성공으로 표현하면 local 검증과 release promotion을
|
||||
5. inventory를 CycloneDX 1.6 SBOM으로 투영한다. component 수, lockfile digest,
|
||||
SRI, license와 dependency edge가 inventory와 일치해야 한다.
|
||||
6. local in-toto/SLSA 형태 provenance statement는 source set, lockfile, SBOM과
|
||||
`dist` digest를 연결하되 `LOCAL_UNSIGNED`로 표시한다. 외부 attestation은
|
||||
provider, signer와 동일 dist subject digest가 있어야 한다.
|
||||
7. vulnerability adapter는 `VULNERABILITY_REPORT_PATH`가 가리키는
|
||||
machine-readable provider report를 검증한다. report의 lock digest, provider,
|
||||
severity와 exception owner/reviewer/reason/expiry가 유효해야 한다.
|
||||
8. provider report가 없으면 local inventory/license/SBOM/coherence는 `PASS`,
|
||||
promotion은 `FAIL_UNVERIFIED`다. 빈 finding을 만들어 vulnerability PASS로
|
||||
표시하지 않는다.
|
||||
9. secret scan은 source, scripts, tests, tracked config/schema, public, `dist`와
|
||||
`dist` digest를 연결하되 `LOCAL_UNSIGNED`로 표시한다. 이 문서는 외부
|
||||
provenance를 대신할 수 없다.
|
||||
7. `immutable_build`는 raw `pnpm-lock.yaml`, `dist`, build/module inventory와
|
||||
모든 local verification evidence를 한 번만 archive한다. Candidate manifest는
|
||||
raw lock bytes SHA-256, dependency inventory lock digest와 manifest
|
||||
`lockfileSha256`의 exact 일치를 요구한다.
|
||||
8. 두 provider job은 동일 archive를 각각 받아 외부 command를 실행한다.
|
||||
Vulnerability report는 raw lock digest와 `distSha256`, provenance attestation은
|
||||
`{name: "dist", digest.sha256}`를 포함한다. 두 문서 모두 strict schema와
|
||||
별도 trust path/key ID로 선택한 실제 Ed25519 public key 서명을 통과해야 한다.
|
||||
9. provider report나 trusted key가 없으면 local
|
||||
inventory/license/SBOM/coherence는 `PASS`, promotion은
|
||||
`FAIL_UNVERIFIED`다. 저장소 generator나 fixture가 production용 빈 finding 또는
|
||||
signed PASS를 만들지 않는다.
|
||||
10. secret scan은 source, scripts, tests, tracked config/schema, public, `dist`와
|
||||
generated release metadata를 검사한다. allowlist는 test path에만 허용하며
|
||||
owner, reason과 expiry가 필요하다. 발견한 secret 원문은 artifact에 쓰지 않고
|
||||
rule, path, line과 fingerprint만 남긴다.
|
||||
10. `SOURCE_DATE_EPOCH`를 지원하고 같은 source/lock/config의 production build를
|
||||
11. `SOURCE_DATE_EPOCH`를 지원하고 supply-chain timestamp도 build manifest의
|
||||
동일 epoch에 결합한다. 같은 source/lock/config의 production build를
|
||||
두 번 실행해 전체 dist digest 일치를 검증한 뒤 일반 build를 복원한다.
|
||||
|
||||
## 실행 경계와 증적
|
||||
@@ -61,8 +68,10 @@ package.json + frozen pnpm-lock.yaml + installed graph
|
||||
|
||||
source/config/lock + production dist
|
||||
-> local provenance statement
|
||||
-> optional vulnerability/attestation provider inputs
|
||||
-> LOCAL PASS | promotion PASS/FAIL_UNVERIFIED
|
||||
-> immutable archive + candidate manifest + distSha256
|
||||
-> external vulnerability provider + external provenance provider
|
||||
-> read-only local revalidation + signature/digest verification
|
||||
-> promotion PASS | FAIL_UNVERIFIED
|
||||
```
|
||||
|
||||
- policy: `config/security/`
|
||||
@@ -82,8 +91,9 @@ source/config/lock + production dist
|
||||
- ordering-only digest, removal, integrity tamper, baseline tamper, high-risk
|
||||
self approval, denied license, critical vulnerability와 만료 exception,
|
||||
provider/digest 오류, SBOM/provenance 불일치 fixture를 검사한다.
|
||||
- synthetic provider/attestation fixture는 promotion `PASS`를 증명한 후 기본
|
||||
`FAIL_UNVERIFIED` 상태를 복원한다.
|
||||
- isolated temporary candidate/PEM/report fixture는 실제 environment path wiring을
|
||||
통해 valid immutable 입력만 promotion `PASS`임을 증명한다. Production artifact를
|
||||
덮어쓰거나 generator를 provider 모드로 재실행하지 않는다.
|
||||
- frozen install은 manifest/lock mismatch fixture를 실제 pnpm으로 거절한다.
|
||||
- source/config/dist 각각의 synthetic secret fixture가 실제 scan을 실패시키고
|
||||
scoped test allowlist만 통과한다.
|
||||
@@ -97,7 +107,7 @@ attestation transparency/retention과 비밀 관리를 결정해야 한다.
|
||||
|
||||
## Rollback
|
||||
|
||||
외부 scanner/attestor adapter는 환경 입력을 제거하면 즉시
|
||||
외부 scanner/attestor command, report path 또는 trusted key 설정을 제거하면 즉시
|
||||
`FAIL_UNVERIFIED`로 돌아간다. local inventory, lock integrity, license, SBOM,
|
||||
secret, reproducibility와 actual diff gate는 유지한다. scanner 장애를 이유로
|
||||
promotion을 PASS로 변경하지 않는다.
|
||||
|
||||
@@ -32,6 +32,16 @@ full commit ID와 commit timestamp를 한 번 읽어 `SOURCE_DATE_EPOCH`를 유
|
||||
release manifest도 같은 build ID, commit SHA, release ID와 timestamp를 가져야
|
||||
한다.
|
||||
|
||||
Release tier의 `immutable_build`는 `dist`의 hidden `.vite` entries, raw
|
||||
`pnpm-lock.yaml`, build/module inventory와 local release/security evidence를 한
|
||||
번 생성해 run ID/attempt로 구분된 archive로 게시한다. Raw lock bytes의 SHA-256은
|
||||
dependency inventory와 candidate manifest 양쪽의 `lockfileSha256`과 같아야 한다.
|
||||
Vulnerability/provenance provider job은 같은 archive를 각각 내려받고
|
||||
`CANDIDATE_LOCKFILE_PATH`, `CANDIDATE_DIST_SHA256`를 외부 command에 전달한다.
|
||||
Promotion은 같은 archive와 두 report를 별도 경로로 내려받은 뒤 local evidence를
|
||||
read-only로 다시 계산하고 Ed25519 signature/digest를 확인한다. Promotion job에는
|
||||
build/rebuild command가 없으며 검증한 archive 자체를 그대로 승격한다.
|
||||
|
||||
Provider baseline은 Gitea 1.26.4 이상과 Gitea Runner 1.0.0 이상이다. 이
|
||||
workflow를 required check로 전환하기 전에 staging instance에서
|
||||
`permissions`, `gitea.run_attempt`, `actions/upload-artifact@v4`를 포함한 한
|
||||
@@ -132,6 +142,15 @@ Repository variables required by higher tiers:
|
||||
- `HOSTING_BASE_URL` for live header verification
|
||||
- `FIELD_WEB_VITALS_INPUT` for the privacy-approved field sample document
|
||||
- `MIN_ELIGIBLE_SAMPLES` after the baseline decision
|
||||
- `VULNERABILITY_PROVIDER_COMMAND` and `PROVENANCE_PROVIDER_COMMAND` for the
|
||||
independently operated scanner and attestor commands
|
||||
- `VULNERABILITY_PUBLIC_KEY_PATH`, `VULNERABILITY_KEY_ID`,
|
||||
`PROVENANCE_PUBLIC_KEY_PATH`, and `PROVENANCE_KEY_ID` for separately managed
|
||||
trusted Ed25519 verification material
|
||||
|
||||
If any external provider command, report, trust path, or key ID is absent,
|
||||
promotion remains unavailable with `FAIL_UNVERIFIED`; there is no local
|
||||
generator/restore fallback.
|
||||
|
||||
Branch protection must mark each `FE-GATE-* / <name>` check required for its
|
||||
declared tier. This repository cannot configure server-side protection by
|
||||
|
||||
@@ -36,14 +36,29 @@ Promotion reads the provider files named by `VULNERABILITY_REPORT_PATH` and
|
||||
exact lockfile digest and candidate `distSha256`; the provenance attestation
|
||||
must name `dist` with that same digest. Both documents use strict schemas and
|
||||
Ed25519 signatures verified with separately configured trusted public keys and
|
||||
key IDs.
|
||||
key IDs (`VULNERABILITY_PUBLIC_KEY_PATH`, `VULNERABILITY_KEY_ID`,
|
||||
`PROVENANCE_PUBLIC_KEY_PATH`, and `PROVENANCE_KEY_ID`). Keys of another curve,
|
||||
including Ed448, are rejected even if a document labels its algorithm
|
||||
`Ed25519`.
|
||||
|
||||
`immutable_build` archives the raw `pnpm-lock.yaml`, `dist` (including hidden
|
||||
`.vite` files), the build manifest, module inventory, release verification,
|
||||
secret-scan result, and local supply-chain evidence once. The candidate
|
||||
manifest hashes the raw lockfile bytes and requires that digest to equal the
|
||||
dependency inventory's `lockfileSha256`. The two provider jobs download this
|
||||
same archive separately and receive `CANDIDATE_LOCKFILE_PATH` and
|
||||
`CANDIDATE_DIST_SHA256`; configured `VULNERABILITY_PROVIDER_COMMAND` and
|
||||
`PROVENANCE_PROVIDER_COMMAND` must emit the signed reports.
|
||||
|
||||
If either provider input is absent, local verification remains meaningful but
|
||||
`artifacts/security/supply-chain-verification.json` records
|
||||
`promotionStatus: FAIL_UNVERIFIED`. `verify:provider-evidence` and
|
||||
`verify:promotion` then exit non-zero. Promotion recomputes the candidate file
|
||||
set and digests and never rebuilds it. Scanner or signing outages are not
|
||||
converted to an empty PASS.
|
||||
set and digests, then read-only revalidates the archived executable schemas,
|
||||
raw lockfile, module inventory, build outputs, release coherence, SBOM,
|
||||
provenance, security scan and supply-chain coherence. It never rebuilds or
|
||||
rewrites candidate evidence. Scanner or signing outages are not converted to
|
||||
an empty PASS.
|
||||
|
||||
Approved vulnerability exceptions require vulnerability/package identity,
|
||||
owner, a different reviewer, reason and expiry. Expired or self-approved
|
||||
|
||||
Reference in New Issue
Block a user