chore(sdk-py): prepare v0.15.0 release (#984) #925
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: "CI: daemon" | |
| on: | |
| push: | |
| branches: [main] | |
| paths: | |
| - "daemon/**" | |
| - "sdk/go/**" | |
| - "sdk/ts/**" | |
| - "sdk/py/**" | |
| pull_request: | |
| branches: [main] | |
| paths: | |
| - "daemon/**" | |
| - "sdk/go/**" | |
| - "sdk/ts/**" | |
| - "sdk/py/**" | |
| permissions: | |
| contents: read | |
| jobs: | |
| test: | |
| # Matrix exercises both Linux (SO_PEERCRED, /proc/<pid>/exe) and macOS | |
| # (LOCAL_PEERCRED, LOCAL_PEEREPID, SYS_PROC_INFO(PROC_PIDPATHINFO)) | |
| # peer-credential paths in CI. fail-fast is off so a darwin-only flake | |
| # doesn't mask a Linux regression and vice versa. | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest] | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6 | |
| with: | |
| # Pin to the patch recorded in daemon/go.mod (ADR-0031) so CI stops | |
| # floating to the latest 1.26.x — a moving toolchain would defeat the | |
| # reproducible-build attestation Gate B asserts. | |
| go-version-file: daemon/go.mod | |
| # Node + pnpm: integration tests spawn the TS emitter helper | |
| # (daemon/helpers/emit_ts.mjs), which imports | |
| # sdk/ts/dist/emitter.js. The dist/ directory is generated by | |
| # `pnpm build`, so we need a Node toolchain and a TS build before | |
| # the Go integration test job runs. Corepack + pnpm version pin | |
| # mirrors .github/workflows/sdk-ts.yml. | |
| # Note: corepack must be enabled before setup-node's cache restoration, | |
| # so we call it in a separate step first. | |
| - run: corepack enable && corepack prepare pnpm@10.33.0 --activate | |
| - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 | |
| with: | |
| node-version: "24" | |
| cache: "pnpm" | |
| cache-dependency-path: sdk/ts/pnpm-lock.yaml | |
| - name: Build TypeScript SDK | |
| working-directory: sdk/ts | |
| run: | | |
| pnpm install --frozen-lockfile | |
| pnpm run build | |
| # uv: integration tests invoke the Python emitter helper via | |
| # `uv run` in sdk/py, so uv must be on PATH. Pin matches | |
| # .github/workflows/sdk-py.yml. | |
| - uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2 | |
| - name: Vet | |
| working-directory: daemon | |
| run: go vet ./... | |
| - name: Build | |
| working-directory: daemon | |
| # -trimpath mirrors the release build (daemon/.goreleaser.yaml): CI must | |
| # exercise the same flags the attestation depends on (ADR-0031). | |
| run: go build -trimpath ./cmd/... | |
| - name: Test | |
| working-directory: daemon | |
| # Single tagged run covers unit + integration tests; the | |
| # `integration` build tag only adds files (it does not exclude | |
| # untagged ones), so this matches the coverage of running | |
| # `go test ./...` and `go test -tags=integration ./...` | |
| # separately, without re-running the untagged tests. | |
| run: go test -race -tags=integration ./... -v | |
| # Gate A (ADR-0031): the daemon keeps a lean import graph that never reaches | |
| # the operator CLI surface. A dependency edge from cmd/obsigna-daemon into the | |
| # receipt/keys/doctor/disclose *cli trees would drag operator-only code into | |
| # the long-running signing process and break the blast-radius claim the | |
| # topology exists to make. The rule lives in a Go test next to the code | |
| # (cmd/obsigna-daemon/import_guard_test.go) so it is enforced locally too and | |
| # auto-catches any new internal/*cli package; this job just runs it. | |
| import-graph: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6 | |
| with: | |
| go-version-file: daemon/go.mod | |
| - name: Assert obsigna-daemon excludes the operator CLI surface | |
| working-directory: daemon | |
| run: go test -run '^TestImportGraphExcludesOperatorSurface$' ./cmd/obsigna-daemon -v | |
| # Gate B (ADR-0031): reproducible build. Build obsigna-daemon twice from two | |
| # working-directory paths of different lengths and assert byte-identical | |
| # sha256. This is what proves -trimpath actually took: without it the absolute | |
| # build path is baked into the binary and the two hashes diverge. The release | |
| # workflow extends this to an independent rebuild that must match the published | |
| # artifact (release-obsigna.yml), which is the auditor-facing attestation. | |
| reproducible-build: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 | |
| - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6 | |
| with: | |
| go-version-file: daemon/go.mod | |
| - name: Build from two different paths, assert identical sha256 | |
| run: | | |
| set -euo pipefail | |
| # Export the tracked tree (no .git, no untracked worktrees) into two | |
| # parent dirs whose paths differ in length, then build the daemon in | |
| # each via the shared reproducible-build script (same determinism flags | |
| # the release attestation uses). The workspace (go.work) is exported | |
| # too, so both builds resolve the in-tree sdk/go identically; the only | |
| # difference between them is the absolute build path. | |
| a=/tmp/p1 | |
| b=/tmp/path-two-longer-than-one | |
| mkdir -p "$a/repo" "$b/repo" | |
| git archive --format=tar HEAD | tar -x -C "$a/repo" | |
| git archive --format=tar HEAD | tar -x -C "$b/repo" | |
| "$a/repo/scripts/reproducible-build.sh" "$a/repo/daemon" /tmp/daemon-a ./cmd/obsigna-daemon | |
| "$b/repo/scripts/reproducible-build.sh" "$b/repo/daemon" /tmp/daemon-b ./cmd/obsigna-daemon | |
| h1="$(sha256sum /tmp/daemon-a | awk '{print $1}')" | |
| h2="$(sha256sum /tmp/daemon-b | awk '{print $1}')" | |
| echo "path-a sha256=$h1" | |
| echo "path-b sha256=$h2" | |
| if [ "$h1" != "$h2" ]; then | |
| echo "::error::obsigna-daemon is not reproducible across build paths ($h1 vs $h2); -trimpath is not taking effect." | |
| exit 1 | |
| fi | |
| echo "ok: byte-identical obsigna-daemon from two different build paths ($h1)" |