refactor(repo): move the dev-install symlinking into its own guarded script #244
Workflow file for this run
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 | |
| on: | |
| pull_request: | |
| types: [opened, synchronize, reopened, ready_for_review] | |
| branches: [develop, main] | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| # Enforce Conventional Commits on every PR. Lightweight — stays on | |
| # GitHub-hosted runners (no self-hosted fallback needed). | |
| commit-lint: | |
| name: Commit Lint | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| if: github.event.pull_request.draft == false | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| - uses: wagoid/commitlint-github-action@v6 | |
| with: | |
| configFile: commitlint.config.mjs | |
| # Lint the shell that puts a binary on someone's PATH: POSIX-only shellcheck | |
| # plus canonical shfmt formatting. Both scripts here are install-path logic | |
| # guarded by D-0004 — install.sh places a released binary, dev-install.sh | |
| # symlinks a build-tree one — which is why they are held to a standard the | |
| # rest of the repo's shell is not. | |
| # Lightweight — stays on GitHub-hosted runners, same as commit-lint. | |
| shell-lint: | |
| name: Shell Lint (install scripts) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| if: github.event.pull_request.draft == false | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Install shfmt | |
| uses: taiki-e/install-action@v2 | |
| with: | |
| tool: shfmt | |
| - name: shellcheck -s sh install.sh dev-install.sh | |
| run: shellcheck -s sh install.sh dev-install.sh | |
| - name: shfmt -d -s -ln posix -i 2 install.sh dev-install.sh | |
| run: shfmt -d -s -ln posix -i 2 install.sh dev-install.sh | |
| # Lint install.ps1: PSScriptAnalyzer at Warning severity, install.sh's Windows sibling. | |
| # Lightweight — stays on GitHub-hosted runners, same as shell-lint above. `shell: pwsh` | |
| # runs PowerShell 7+ (only what ubuntu-latest ships); install.ps1's own compatibility | |
| # floor is Windows PowerShell 5.1, but PSScriptAnalyzer's rules are version-agnostic | |
| # static analysis, so linting under pwsh here still catches what matters. | |
| powershell-lint: | |
| name: PowerShell Lint (install.ps1) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| if: github.event.pull_request.draft == false | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Invoke-ScriptAnalyzer install.ps1 | |
| shell: pwsh | |
| run: | | |
| Install-Module PSScriptAnalyzer -Force -Scope CurrentUser | |
| Invoke-ScriptAnalyzer -Path install.ps1 -Severity Warning -EnableExit | |
| # Dependency license gate. Renovate auto-merges minor/patch bumps, so without | |
| # this a transitive copyleft dep can reach a release build with nobody reading | |
| # a diff. Policy + per-crate carve-outs live in deny.toml. Licenses only — | |
| # advisories are deliberately not gated on the PR path (see deny.toml). | |
| licenses: | |
| name: Dependency licenses | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| if: github.event.pull_request.draft == false | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Install cargo-deny | |
| uses: taiki-e/install-action@v2 | |
| with: | |
| tool: cargo-deny | |
| - name: cargo deny check licenses | |
| run: cargo deny check licenses | |
| # GitHub-hosted, never self-hosted. This job builds and runs a contributor's | |
| # code (`cargo test`, `build.rs`, proc-macro expansion) straight off a | |
| # `pull_request` trigger, so on a public repo it is arbitrary code execution | |
| # by anyone who can get a PR approved. The org's `self-hosted,build` pool is | |
| # persistent and lives inside our network — one poisoned PR there buys | |
| # lateral access and a foothold that survives into later legitimate runs. | |
| # Ephemeral GitHub-hosted runners bound that blast radius to a throwaway VM. | |
| # `build-release.yml` still uses the self-hosted pool: it triggers only on | |
| # `workflow_run`/`workflow_dispatch`, which a fork PR cannot reach. | |
| rust: | |
| name: Rust (capture layer) | |
| runs-on: ubuntu-latest | |
| if: github.event.pull_request.draft == false | |
| env: | |
| RUST_BACKTRACE: "1" | |
| steps: | |
| - uses: actions/checkout@v7 | |
| # Set up the Rust toolchain directly instead of via mise — mise's | |
| # `rust = "stable"` is a silent no-op on runners without rustup. The | |
| # GitHub-hosted images ship rustup, so this just pins stable and adds | |
| # the components fmt/clippy need. | |
| - name: Set up Rust toolchain | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| rustup toolchain install stable --profile minimal | |
| rustup default stable | |
| rustup component add rustfmt clippy | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: fmt | |
| run: cargo fmt --all -- --check | |
| - name: clippy | |
| run: cargo clippy --workspace --all-targets -- -D warnings | |
| - name: test | |
| run: cargo test --workspace | |
| # Diff EVERY schema emit-schema writes, not just attestation. The cloud | |
| # generates its Zod/TS from these files, so a stale one ships a wrong | |
| # boundary downstream while this job stays green — which is exactly the | |
| # hole knowledge.schema.json sat in: a KnowledgeDecision/KnowledgeSpec | |
| # field addition leaves attestation.schema.json byte-identical. | |
| - name: contract schemas are up to date | |
| run: | | |
| cargo run -q -p dira-contract --bin emit-schema | |
| git diff --exit-code contract/*.schema.json \ | |
| || (echo "a contract schema is stale — run 'just contract-schema'"; exit 1) | |
| - name: signing vector fixture is up to date | |
| run: | | |
| cargo run -q -p dira-core --bin sign_vector > contract/testdata/signing-vector.json | |
| git diff --exit-code contract/testdata/signing-vector.json \ | |
| || (echo "signing-vector fixture is stale — run 'just vector'"; exit 1) | |
| # Windows build/test lane (native, not WSL): validates the named-pipe IPC transport | |
| # (`cli/ipc`) and everything else in the workspace on the actual target platform. | |
| # Independent of `rust` above — fmt/contract-schema stay Linux-only intentionally | |
| # (see module doc), so this job only runs clippy + tests. | |
| rust-windows: | |
| name: Rust (windows) | |
| runs-on: windows-latest | |
| if: github.event.pull_request.draft == false | |
| timeout-minutes: 30 | |
| env: | |
| RUST_BACKTRACE: "1" | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - name: Set up Rust toolchain | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| rustup toolchain install stable --profile minimal | |
| rustup default stable | |
| rustup component add clippy | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: clippy | |
| run: cargo clippy --workspace --all-targets -- -D warnings | |
| - name: test | |
| run: cargo test --workspace | |
| # Proves `.cargo/config.toml`'s `+crt-static` actually takes effect, from | |
| # THIS branch's source (#60). build-release.yml carries the same assertion, | |
| # but that job checks out `refs/tags/<tag>` — so it can only ever validate a | |
| # tag that already contains the fix, never a change under review. That | |
| # distinction cost a confused debugging round; keep both. | |
| # Debug build: linkage is set per-target in .cargo/config.toml and applies | |
| # to every profile, and the dependency graph is already warm from the two | |
| # steps above, so this costs seconds. | |
| - name: CRT is linked statically | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = 'Stop' | |
| cargo build --bin dira --bin dirad | |
| if ($LASTEXITCODE -ne 0) { throw "cargo build failed (exit $LASTEXITCODE)" } | |
| $bad = @() | |
| foreach ($name in 'dira', 'dirad') { | |
| $exe = "target/debug/$name.exe" | |
| if (-not (Test-Path $exe)) { throw "expected $exe to exist" } | |
| $text = [Text.Encoding]::ASCII.GetString([IO.File]::ReadAllBytes($exe)) | |
| foreach ($dll in 'VCRUNTIME140', 'api-ms-win-crt-runtime') { | |
| if ($text -match [regex]::Escape($dll)) { $bad += "$name.exe imports $dll" } | |
| } | |
| } | |
| if ($bad) { | |
| throw "dynamic CRT -- these would need the VC++ Redistributable: $($bad -join '; ')" | |
| } | |
| Write-Host "both binaries link the CRT statically" |