Skip to content

Releases: NDDev-it-com/ci-workflows

0.13.2

Choose a tag to compare

@github-actions github-actions released this 01 Aug 15:55
Immutable release. Only release title and notes can be modified.
0.13.2
913f1a1

Fixed

  • zizmor-sarif.yml never declared the actions: read its SARIF upload
    needs.
    github/codeql-action/upload-sarif reads the workflow run, so it
    requires actions: read; public-codeql.yml — the other SARIF uploader here —
    declares it, and this one did not. The incomplete set had propagated into
    catalog/capabilities.yml and all four examples that call it. Consumers saw
    the scan succeed and the upload fail with Resource not accessible by integration; observed on github-device-sync, red since adoption. Reusable,
    catalog, examples and this repository's own ci.yml caller now declare the
    same set.

    A caller cannot grant a reusable less than the reusable declares, so the token
    comes from the called workflow: a consumer cannot work around this by adding
    the permission to its own caller — it needs a release carrying the fix.

Added

  • public-scorecard.yml was the only reusable without a copy-paste example.
    examples/public-oss/scorecard.yml covered the JSON variant only, so the
    SARIF-uploading variant — the one that needs security-events: write and
    turns Scorecard findings into persistent code-scanning alerts — had no
    validated caller. Adds examples/public-oss/scorecard-sarif.yml, including
    the reason to pick one variant over the other and the shared trigger
    constraint. Every reusable now has an example.

0.13.1

Choose a tag to compare

@github-actions github-actions released this 01 Aug 14:34
Immutable release. Only release title and notes can be modified.
0.13.1
df562bc

Fixed

  • Five reusables were self-applied but still recorded as unverified. When
    codeql.yml, gitleaks.yml, dependency-review.yml, and scorecard.yml were
    added as self workflows calling their reusables through relative refs, the
    runtime-coverage ledger was never updated to match — so the repository was
    proving these workflows on every push while the ledger claimed no observed run
    existed. Promoted to runtime-proven against runs that executed the current
    bytes: public-codeql.yml, secret-scan.yml, public-scorecard-json.yml,
    zizmor-sarif.yml, public-dependency-review.yml. Runtime-proven entries go
    from one to six.

    Nothing was promoted on estate evidence, although consumer repositories did run
    several of these today: every such run executed an older pinned revision, and a
    proof is only valid for the bytes it exercised. That tension is structural — a
    dependency bump invalidates a proof — which is why sustainable coverage comes
    from self-calling fixtures rather than from opportunistically harvesting
    consumer runs.

Added

  • New skill ci-consumer-adoption. The skill set covered authoring and
    operating the library but nothing about wiring a consumer repository onto
    it, which is where the two observed failure shapes live: a repository that
    looks configured but still bills, and a repository routed to hardware its jobs
    cannot use. Covers tier selection from entitlements rather than visibility
    alone, pinning to a released tag by full SHA, runner routing by visibility,
    the two managed scans no workflow file can reach, and proving the routing from
    a completed run's runner_name instead of a saved setting.

Changed

  • ci-cost-performance gains the visibility-routing rule and its corollaries:
    self-hosting pays only where minutes are metered, moving public work onto own
    hardware buys a fork-PR execution path rather than a saving, platform-scheduled
    scans carry their own runner control, there is no spillover from a busy
    self-hosted label to a hosted runner, and an isolated self-hosted runner is
    unprivileged so system-path installs fail there.

0.13.0

Choose a tag to compare

@github-actions github-actions released this 01 Aug 13:51
Immutable release. Only release title and notes can be modified.
0.13.0
77cd5f0

Added

  • GitHub Code Quality is now a modelled tier instead of an unattached price
    tag.
    The product existed in the ledger as github-code-quality-transition
    and nowhere else: no capability, no tier doc, no mention in the tier tables —
    so the catalog priced a product it never told adopters how to place. It gets
    catalog/capabilities.yml entry github-code-quality and a tier doc,
    docs/16-code-quality.md.

    It is deliberately not folded into the public tier. Re-verification
    against the billing docs on 2026-08-01 established that visibility does not
    gate the licence: a public repository is billed the same per-active-committer
    rate as a private one, and being public only removes the Actions-minutes
    component. That contradicted docs/01-public-oss-free.md, which promised the
    "entire security and supply-chain suite for free" — a claim that would have
    been false for any adopter who enabled Code Quality on a public repo. The
    three-tier model sorts by visibility and plan; this product obeys neither, so
    it is documented as an orthogonal fourth tier and excluded from both free
    tiers, with the free maintainability substitutes (coverage-gate.yml,
    docs-quality.yml, pr-hygiene.yml, zizmor, the language packs) named
    explicitly.

    Two further billing facts are now recorded because they invert the usual
    cost-control instinct: committers are counted once per organization, so
    enabling one repository already bills the whole active-committer set and a
    "few paid repos, many free repos" split saves nothing unless the committer
    sets actually differ; and the licence is independent of Code Security and
    Secret Protection, so GHAS does not include it and holding both means paying
    two products to drive one CodeQL engine.

    The capability carries workflow: null and example: null, which is the
    honest shape rather than a gap: Code Quality has no Action, no workflow_call
    entrypoint, and no REST or GraphQL API, so enablement is UI-only and cannot be
    pinned by SHA, asserted, or drift-checked from CI. For the same reason the
    merge gate — ruleset rule "Require code quality results", severity threshold,
    check CodeQL - Code Quality — is documented as a UI procedure and not
    encoded in .github/rulesets/: those specs are shaped for
    POST /repos/{owner}/{repo}/rulesets and the rule-type identifier for this
    rule is undocumented. AGENTS.md records the gate so the next contributor does
    not re-derive it, replacing a stale instruction to "refresh that fact" on a
    date that has passed.

  • The library described GitHub's price list, not this estate's receipts.
    Every tier doc reasoned from what GitHub charges a hypothetical adopter, so a
    private NDDev repository was configured as if it were on the free plan while
    the organization was already paying for Enterprise Cloud, Code Security,
    Secret Protection, and Code Quality. docs/17-nddev-tier.md records the
    verified entitlements and the advice that consequently does not apply.

    The concrete loss this closes: docs/02-private-free.md routes private
    releases to release-supply-chain-free.yml because Artifact Attestations
    require Enterprise Cloud on private repos. This estate has Enterprise
    Cloud, so all 26 private repositories were emitting slsa_build_level: null
    and discarding provenance that was already bought. They can use the attested
    release-supply-chain.yml.

    Also recorded, because it inverts the usual cost instinct: these products bill
    per active committer counted once per organization, so with one committer
    the estate pays the same whether one repository or fifty are enabled — partial
    coverage would have cost identically and protected less. examples/nddev/
    joins the aggregate-example allowlist in validate_catalog.py, alongside the
    three existing per-tier security suites.

    The doc is explicit about what is absent too: Copilot Autofix is unavailable
    (Copilot Business provisioned, zero seats assigned), and SHA pinning is
    unenforced at both org and enterprise (sha_pinning_required: false) — flagged
    rather than recommended blindly, since enabling it org-wide would break any
    repository still pinning actions by tag.

Fixed

  • A grouped action bump could not land on its own. Dependabot updates the
    uses: pins inside the workflows but knows nothing about catalog/tools.yml,
    so validate_catalog.py failed on seven tools whose catalog pin no longer
    matched the workflow that used it, and validate_runtime_coverage.py failed
    because two workflow files changed after the run that proved them. Catalog
    pins and current_version synced for attest, checkout, setup-python,
    setup-go, setup-dotnet, labeler, and markdownlint-cli2-action.
    actionlint.yml is re-proven against the CI run that executed the new bytes —
    this repository's own ci.yml calls it through a relative ref, so the proof is
    real. release-supply-chain.yml is downgraded to static-only: nothing in
    this repository's CI calls it, so no run has executed the new bytes, and the
    ledger's rule is to downgrade rather than carry a stale proof. The next real
    release re-proves it.

  • The catalog recorded four action pins that no workflow used. setup-node,
    setup-java, setup-swift, and checkov-action had drifted a version behind
    the SHA their used_by workflows actually reference — setup-swift by a full
    major (v2.4.0 recorded, v3 shipped). validate_catalog.py checked only the
    pin's shape and that used_by paths existed, never that the pin matched
    reality, so the gate stayed green while the declared source of truth was wrong
    in four places. Pins synced and validate_catalog.py now fails when a
    catalog pin does not appear verbatim in each of its used_by workflows.

  • sql-ci.yml declared a python_version input that nothing read. It was
    the only never-read input across all reusables; the workflow has no
    setup-python step at all and provisions Python through setup-uv. A caller
    passing it got a silently ignored value. Input removed and the header comment
    corrected from "pinned setup-python" to "pinned setup-uv".

  • docs/12-community-dx.md listed five community-health files as still missing;
    all five have shipped. Only the optional .github/FUNDING.yml remains absent.

Added

  • Self-application of the public OSS security suite. This repository shipped
    CodeQL, OSSF Scorecard, Dependency Review, and gitleaks to the estate while
    consuming none of them itself; it self-applied only actionlint, zizmor,
    and release-supply-chain. New self workflows codeql.yml, gitleaks.yml,
    dependency-review.yml, and scorecard.yml call the matching reusables
    through relative refs, with triggers taken from this repository's own
    examples/public-oss/ shapes.

Fixed

  • SELF_WORKFLOWS was duplicated as a literal in three places.
    _workflow_yaml.py held the named constant while validate_catalog.py and
    generate_docs.py each hardcoded {"ci.yml", "release.yml"} again. Both now
    import it. With the constant honoured in only one of the three,
    validate_all.py passed while docs/generated/workflow-inventory.md listed
    the new self workflows as MISSING instead of internal — a green gate over
    wrong generated output.

  • Pinned tools installed into /usr/local/bin, which no correctly isolated
    self-hosted runner allows.
    actionlint.yml and osv-scan.yml placed their
    checksum-verified binaries in a system path. That works on GitHub-hosted
    runners, where the job user may write there, and fails outright on a
    self-hosted runner whose account is unprivileged:
    install: cannot create regular file '/usr/local/bin/actionlint': Permission denied.
    Found by routing a real private-repository job to a self-hosted runner. The
    privilege is not incidental — a runner that can write to system paths shares
    mutable state between jobs — so the destination moved rather than the runner's
    permissions: both now install into "${RUNNER_TEMP}/bin" and prepend it to
    GITHUB_PATH, which is writable on hosted and self-hosted alike and is torn
    down with the job. Checksum verification is unchanged. cpp-ci.yml still uses
    sudo apt-get; that is a different class (system packages, not one pinned
    binary) and remains hosted-only.

Documentation

  • No documented rule for which repositories run where. Private-repository
    minutes are metered and public ones are free, so the cost-optimal routing is
    private → self-hosted, public → GitHub-hosted. docs/05-runners.md gains
    Routing by visibility with that rule, the fork-PR reasoning that makes a
    self-hosted runner on a public repository a security defect rather than a
    saving, and an explicit statement that this repository is public and must
    never route itself to self-hosted or ship a self-hosted default in
    examples/.
  • Two runner settings are invisible to workflow files. CodeQL default
    setup
    and Code Quality scans are scheduled by GitHub, not by a workflow,
    and each carries its own runner control. Missing either leaves a repository
    consuming metered minutes while every caller says otherwise. Both are now
    documented with the exact API call and UI path.
  • AI findings were undocumented. docs/16-code-quality.md gains an
    AI findings section: they are metered separately from the per-committer
    licence with no included allowance (discountAmount: 0.00 on every
    billing line, $0.01/credit), and one repository burned 774.9 credits in about
    twelve days — roughly twice the licence that covers a whole organization. Also
    records why a product budget cannot fence this off, and that the switch is
    absent entirely where CodeQL finds no supported language.
  • docs/17-nddev-tier.md gains the verified per-line cost envelope and a runner
    routing summary, and...
Read more

0.12.0

Choose a tag to compare

@github-actions github-actions released this 21 Jul 05:45
Immutable release. Only release title and notes can be modified.
2ccb80e

Changed

  • Repository renamed nddev-ci-workflowsci-workflows. Every active
    and identity surface now uses the new coordinate: release package_name,
    all examples/** reusable uses: refs, README/docs/skills, and the two
    gate-coupled slugs (check_examples.py USES_RE, validate_runtime_coverage.py
    REPO_SLUG + runtime-coverage.yml run URLs). Consumers must repin reusable
    uses: references to NDDev-it-com/ci-workflows/… (GitHub does not redirect
    uses: across a rename).
  • Pin previously-mutable uv/bun tool versions: semgrep-ci semgrep_version
    default 1.170.0, sql-ci sqlfluff_version default 4.2.2, and the
    web-ci default lint_command now pins stylelint@17.14.1 +
    htmlhint@1.9.2. Empty/bare versions previously floated to the latest
    release at run time.

Added

  • check_tool_pinning validator (wired into validate_all): rejects empty
    uv/bun tool-version inputs and bare uvx/bunx <tool> invocations, keeping
    tool versions as reproducible as the full-SHA action pins.

0.11.3 — Dependabot action bumps

Choose a tag to compare

@rldyourmnd rldyourmnd released this 21 Jul 03:35
Immutable release. Only release title and notes can be modified.
7af0cbb

Bump pinned GitHub Actions (setup-node v7, setup-java v5.6, checkov-action v12.3114, setup-swift v3); iac-scan runtime-coverage downgraded to unverified pending re-run.

0.11.2 — uv 0.11.30 + fact refresh

Choose a tag to compare

@rldyourmnd rldyourmnd released this 21 Jul 01:17
Immutable release. Only release title and notes can be modified.
df2c918

Bump pinned uv 0.11.29->0.11.30 across setup-uv workflows + examples; refresh the github-code-quality-transition product fact (GA/paid transition completed 2026-07-20).

0.11.1 — uv/bun-only reusable CI

Choose a tag to compare

@rldyourmnd rldyourmnd released this 20 Jul 17:25
Immutable release. Only release title and notes can be modified.
bcb4d28

Breaking: all reusable workflows + examples migrated to uv/bun (RVR-P1-001). SHA-pinned setup-uv v8.3.2 + setup-bun v2.2.0, frozen locks, no pip/npm. Module renamed to ci-workflows. (Supersedes burned 0.11.0 tag.)

0.10.0

Choose a tag to compare

@github-actions github-actions released this 12 Jul 01:12
Immutable release. Only release title and notes can be modified.
0.10.0
eb7bd95

Added

  • Three repository-operation skills for agents under .agents/skills/
    (mirrored to .claude/skills/): nddev-repo-orientation (instant mental
    model, file map, contract index, and a task router), nddev-change-flow (the
    complete golden-path checklist, including paired-variant mirroring and the
    runtime-coverage "static-only dance"), and nddev-release-flow (version prep,
    the signed tag, the immutable-release verification checklist, and the
    post-release ledger re-promotion). They complement the eight portable
    CI/GitHub-Actions doctrine skills and route to the catalog and agent
    instructions as the source of truth rather than duplicating volatile facts.
    EXPECTED_SKILLS and the AGENTS.md / .claude/CLAUDE.md skill sections now
    describe the two groups.

Changed

  • Re-promote the release-supply-chain.yml runtime-coverage record to
    runtime-proven after the 0.9.0 release run
    (…/actions/runs/29173277373 at e27d4e3) re-executed the current workflow
    live, recording the fresh run URL and proven_digest. Completes the honesty
    cycle opened when RVR-P2-011 edited the workflow and correctly dropped it to
    static-only.

0.9.0

Choose a tag to compare

@github-actions github-actions released this 12 Jul 00:10
Immutable release. Only release title and notes can be modified.
0.9.0
e27d4e3

Fixed

  • Sync the attested-release permission + Syft contract into every
    consumer-facing surface.
    0.8.1 added artifact-metadata: write to the
    attesting jobs and bumped Syft to 1.46.0 in the workflows and release
    validator, but the caller-facing docs, examples, and catalog still showed
    the old three-scope set and Syft 1.42.3. Because a caller's GITHUB_TOKEN
    permissions are the ceiling for a reusable workflow, a consumer copying the
    stale three-scope example under-scopes the attest step. Update the
    release-supply-chain.yml caller permissions in README.md,
    examples/public-oss/release.yml, and docs/04/docs/09; add
    artifact-metadata: write to the artifact-attestations,
    slsa-build-provenance, and attested releases-packages capabilities in
    catalog/capabilities.yml; correct the Syft version in README.md,
    docs/07, and docs/13; and add a 0.8.1 caller migration note. Contract-
    truth synchronization only — no workflow behavior change.

  • Remove volatile GitHub tariffs from the ci-free-tier-planner skill and
    guard against regression.
    .agents/skills/ci-free-tier-planner/SKILL.md
    hard-coded plan quotas (Actions minute allowances, storage/cache sizes, and
    the attestation / dependency-review / secret-protection / environment plan
    gates), contradicting the project rule that volatile plan/price/quota facts
    live only in the freshness-enforced catalog/product-facts.yml. A product
    fact could expire and correctly redden the ledger while the skill still
    served the stale number. Rewrite section 4 to hold the durable procedure and
    reference the facts by id (github-actions-*, github-attestations-*,
    github-dependency-review-*, github-secret-scanning-*,
    github-environments-*, github-code-quality-transition) with fail-closed
    resolution, and add a check_skills.py guard (with self-test) that fails CI
    if any SKILL.md reintroduces a comma-grouped allowance, <n> minutes, or a
    storage-size figure. Regenerate the .claude/skills mirror. Found by an
    independent forensic review (RVR-P2-010).

  • Harden the runtime-coverage honesty gate against weak and stale proofs.
    validate_runtime_coverage.py accepted any https URL for a
    runtime-proven record (its own fixture used example.invalid), so a docs
    page or a foreign-repo run would have passed, and it never noticed that the
    release-supply-chain.yml record still pointed at a 0.7.0 run
    (…/29165402032 at eda8ff7) taken two edits before the current file.
    Require last_run to be a
    github.com/NDDev-it-com/nddev-ci-workflows/actions/runs/<id> URL and add a
    proven_digest (sha256 of the workflow file at the proving run) that the
    validator recomputes and matches, so any later edit to a proven workflow
    reddens CI until it is re-run and re-recorded (or downgraded) instead of
    silently keeping the label. Repoint all three runtime-proven records to runs
    that provably executed the current bytes (actionlint / zizmor-sarif → the
    ci.yml run …/29172553315; release-supply-chain → the 0.8.1 release run
    …/29167958787 at 8b8e3ea) and record each digest. Fixtures now cover
    foreign-URL, non-run-URL, missing-digest, and stale-digest. Found by an
    independent forensic review (RVR-P2-009).

  • Bound the optional runtime bundle to the SBOM-covered source archive
    (RVR-P2-011).
    release-supply-chain.yml and its byte-parallel free twin
    attach an optional second runtime_paths bundle that received a
    build-provenance attestation but no SBOM — and because runtime_paths was
    validated independently of archive_paths, it could ship tracked files the
    Syft scan of the source payload never saw. Enforce runtime_paths ⊆ archive_paths inside the deterministic-bundle program (both variants,
    byte-identically) so every file in the runtime bundle is also in the source
    archive that sbom.spdx.json inventories — the source SBOM is now provably a
    superset of everything the release ships. Add a check_release_supply_chain.py
    fixture (the runtime-bundle program was previously the one embedded program
    with no hermetic test) covering subset-accepted and outside-archive / absolute
    / unmatched / empty-archive-refused. The release-supply-chain.yml
    runtime-coverage record drops to static-only (its contract validator stands
    in) until the next release re-proves it live. Found by an independent forensic
    review.

Changed

  • Catalog tool inventory + currency (catalog/tools.yml). Add the seven
    in-use actions that were absent from the catalog — actions/setup-node,
    actions/setup-go, actions-rust-lang/setup-rust-toolchain,
    actions/setup-dotnet, actions/setup-java, hashicorp/setup-terraform,
    and aquasecurity/trivy-action — and correct github/codeql-action's
    used_by (it also runs in zizmor-sarif.yml and public-scorecard.yml).
    Bump drifted pins to latest across the workflows and catalog in lockstep:
    codeql-action v4.36.3→v4.37.0, lychee-action v2.8.0→v2.9.0, labeler
    v6.1.0→v6.2.0, stale v10.3.0→v10.4.0, setup-java v5.4.0→v5.5.0, and the
    documented semgrep CLI version v1.168.0→v1.169.0. All remain full-SHA pinned
    with # vX.Y.Z comments; no workflow behavior change.

0.8.1

Choose a tag to compare

@github-actions github-actions released this 11 Jul 20:58
Immutable release. Only release title and notes can be modified.
0.8.1
8b8e3ea

Fixed

  • Grant artifact-metadata: write to the attesting release jobs.
    actions/attest@v4.1.1 documents id-token: write + attestations: write
    • artifact-metadata: write as its required permission set; the release
      jobs in release-supply-chain.yml and release.yml were missing
      artifact-metadata: write, so the action's artifact-storage-record step
      ran without its scope (the Sigstore signing/attestation itself still
      succeeds, which is why past releases passed). Add the scope to both jobs and
      to the release validator's exact attested-permission assertion. The
      attestation-free variant is unaffected (it has no attest steps). Found by a
      deep review against the actions/attest README at the pinned tag.

Changed

  • Relabel the release provenance claim from "SLSA v1.0" to "SLSA v1" in the
    workflow header, README, and SECURITY.md. slsa.dev has retired v1.0 (v1.2 is
    current); the reusable-workflow → Build L3 mechanism is unchanged across
    v1.1/v1.2, so only the version label needed correcting.
  • Bump the checksum-pinned Syft SBOM generator from 1.42.3 to 1.46.0 (latest)
    in both release-supply-chain.yml and release-supply-chain-free.yml, with
    the release validator's SYFT_PINS and catalog/tools.yml updated in
    lockstep (new Linux amd64/arm64 archive sizes and SHA-256s verified against
    the upstream syft_1.46.0_checksums.txt). Syft is a manually pinned binary
    outside Dependabot's reach, so it had drifted four minor versions behind;
    this is a currency/best-practice pass, not a contract change — the SPDX-JSON
    output and every archive/SBOM/manifest/checksum invariant are unchanged.