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
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ benchmarks/results/*
!benchmarks/results/.gitkeep
docs/*
!docs/api-keys.md
!docs/self-hosted-release-evidence.md
*.log*
*.tmp
*.swp
Expand Down
35 changes: 25 additions & 10 deletions .github/workflows/self-hosted-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,14 @@ jobs:
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
node-version: 24.18.0
cache: pnpm
- name: Verify annotated release identity before repository code
shell: bash
run: |
set -euo pipefail
node scripts/verify-self-hosted-release-tag.ts \
--repository "${GITHUB_WORKSPACE}" \
--ref "${GITHUB_REF}" \
--sha "${GITHUB_SHA}"
- run:
corepack enable && corepack prepare "pnpm@${PNPM_VERSION}" --activate
- run: pnpm install --frozen-lockfile
Expand Down Expand Up @@ -196,27 +203,29 @@ jobs:
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
with:
fetch-depth: 0
persist-credentials: false
- uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1
with:
version: 11.21.0
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
node-version: 24.18.0
cache: pnpm
- run: pnpm install --frozen-lockfile
- name: Complete all source gates before signing
run:
pnpm format:check && pnpm lint && pnpm typecheck && pnpm build && pnpm
test
- id: release
shell: bash
run: |
set -euo pipefail
node scripts/verify-self-hosted-release-tag.ts \
--repository "${GITHUB_WORKSPACE}" \
--ref "${GITHUB_REF}" \
--sha "${GITHUB_SHA}"
version="$(node -p "require('./package.json').version")"
test "${GITHUB_REF}" = "refs/tags/self-hosted-v${version}"
test "$(git rev-parse HEAD)" = "${GITHUB_SHA}"
printf 'version=%s\n' "${version}" >> "${GITHUB_OUTPUT}"
- run: pnpm install --frozen-lockfile
- name: Complete all source gates before signing
run:
pnpm format:check && pnpm lint && pnpm typecheck && pnpm build && pnpm
test
- name: Acquire and verify pinned Cosign
shell: bash
env:
Expand Down Expand Up @@ -323,6 +332,12 @@ jobs:
"${ARCH}"
cp distribution/self-hosted/trust-policy.v1.json \
"${RUNNER_TEMP}/release-${ARCH}/skillwire-trust-policy-v1.json"
manifest="${RUNNER_TEMP}/release-${ARCH}/skillwire-${VERSION}-linux-${ARCH}.release.json"
node scripts/verify-self-hosted-release-tag.ts \
--repository "${GITHUB_WORKSPACE}" \
--ref "${GITHUB_REF}" \
--sha "${GITHUB_SHA}" \
--manifest "${manifest}"
- name: Sign external canonical manifest
shell: bash
env:
Expand Down Expand Up @@ -498,4 +513,4 @@ jobs:
assets[index]="release-assets/${assets[index]}"
done
gh release create "${GITHUB_REF_NAME}" "${assets[@]}" \
--verify-tag --title "SkillWire self-hosted ${VERSION}"
--verify-tag --title "SkillWire Self-Hosted v${VERSION}"
16 changes: 13 additions & 3 deletions distribution/self-hosted/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ Do not use `latest`, `curl | sh`, an unverified package manager, or a Cosign
binary shipped only inside the candidate archive. Obtain the current Sigstore
production `trusted_root.json` through its signed TUF repository and verify its
SHA-256 against the trust policy. The first source-pinned root in this release
is `distribution/self-hosted/trusted-root.v1.json`.
is `distribution/self-hosted/trusted-root.v1.json`. Its media type must be
exactly `application/vnd.dev.sigstore.trustedroot+json;version=0.1`, the only
value accepted by the Cosign 3.1.3 / sigstore-go 1.2.2 loader. Do not substitute
the unsupported `application/vnd.dev.sigstore.trustedroot.v0.2+json` value.

## 2. Verify the signed external manifest offline

Expand All @@ -42,6 +45,11 @@ overlap quorum of two, a second sibling bundle named
manifest names both signer IDs and both exact bundle paths; an extra bundle is
never accepted by convention alone.

The manifest names bundle files and signer IDs but never contains bundle bytes,
media types, or digests. Each bundle signs the exact canonical manifest bytes;
including its own digest in that manifest would be circular. Cosign, the exact
certificate claims, and the manifest message digest bind the external bundle.

Disconnect outbound networking (or run inside an already network-isolated
namespace) and invoke the independently verified Cosign directly:

Expand All @@ -61,8 +69,10 @@ cosign verify-blob \
skillwire-VERSION-linux-ARCH.release.json
```

The version and source commit are fields of the canonical manifest; compare them
to the protected tag independently before using them in the command. Never add
The version and source commit are fields of the canonical manifest. The only
accepted tag is the annotated `self-hosted-vVERSION` tag; recursively peel it,
require the result to equal the manifest source commit, and require that commit
to be reachable from protected `main` before using it in the command. Never add
an insecure SCT/transparency bypass or a regular-expression identity.
Verification must finish without a network lookup.

Expand Down
Loading