Skip to content

GitHub Action Package

Reusable GitHub Actions published through action.yml and consumed by workflows.

Charter status

Charter status Value
Maturity Candidate rubric
What this state means Numbered candidate rules carry severity, required evidence, and an exception policy. A versioned rubric can be cut from this page once its promotion criteria are met.
Full rubric Not authored yet. This page is a charter, not a judgeable standard.
Reference implementation vibecodeqa/ref-github-action-package (published) — see Reference implementation below.
Blocking promotion Matured from a backlog note on 2026-08-09 (#37): candidate rules, upstream references, severity, exception policy, and CI evidence are on the page, and ref-github-action-package is now published in the catalog with a self-reported score, a green CI run, and a hand-argued R-GHA-1 to R-GHA-10 mapping (#44). Blocking v1: that mapping is prose rather than a scanner signal, no independent assessment of the repo exists, no release tag has been cut so R-GHA-8 is documented but never exercised, and the composite and Docker runtimes are still unseparated from the JavaScript rules.

Maturity states are defined in Standards Authoring. Metadata lives in standards/registry.json.

Full rubric

No full versioned rubric has been authored yet.

Reference implementation

Score evidence Value
Repository vibecodeqa/ref-github-action-package (published)
VCQA report A 100/100
Verification self-reported
Assessed commit fd8722d
Assessed on 2026-08-09
CI run success (2026-08-08)
Independent assessment None published yet. The score above is the reference repo's own claim, not third-party proof.
Catalog entry last verified 2026-08-09

Teaching focus

This standard teaches that a published action runs inside somebody else's repository, with that repository's token. The consumer picks a version string, grants a set of permissions, and hands over untrusted workflow context; from then on the action's metadata, its pinning policy, and its handling of that token are the whole security boundary. Choosing this stack means treating action.yml, the release tag, and the built artifact as a public contract before adding features.

The three action runtimes are not interchangeable here. A JavaScript action ships a bundled artifact the consumer never builds, a composite action re-runs other actions under the caller's permissions, and a Docker action pulls an image. Rules below say which runtime each one applies to rather than pretending they are one shape.

Scope

Reusable GitHub Actions published through action.yml and consumed by workflows.

Not in scope

  • ordinary workflows in .github/workflows
  • CLIs that are not packaged as actions
  • GitHub Apps
  • reusable workflows (workflow_call), which have their own input and permission model

Composes

Upstream references

VCQA-owned rule surface

  • action.yml metadata completeness.
  • input/output contract and declared-versus-read drift.
  • minimum token permissions in the action's own documented examples.
  • input validation before filesystem, network, or API side effects.
  • secret-input masking and log/output leakage.
  • bundled-artifact freshness for JavaScript actions.
  • failure signalling through the action protocol.
  • pinned runtime and dependency policy, including uses: pinning inside composite actions.
  • release tag policy and consumer pinning guidance.
  • consumer-shaped smoke evidence.

Detection signals

  • action.yml or action.yaml at the repository or directory root
  • runs.using: node20/node22 (JavaScript), composite, or docker
  • declared inputs, outputs, and branding blocks
  • runs.main, runs.pre, runs.post, or runs.steps
  • a committed dist/ bundle alongside src/ for JavaScript actions
  • @actions/core, @actions/github, @actions/exec, or @actions/tool-cache dependencies
  • uses: entries inside runs.steps for composite actions
  • Dockerfile plus runs.image for Docker actions
  • README workflow examples containing uses: <owner>/<repo>@
  • release tags (vX, vX.Y.Z) and a tag-moving release workflow
  • a committed lockfile and a bundler config (esbuild, ncc, or equivalent)

Combination-born guidelines

  • Document minimum GITHUB_TOKEN permissions for every example workflow.
  • Inputs are validated before filesystem, network, or deployment side effects.
  • Release tags and built artifacts must make consumer pinning reliable.
  • A composite action inherits the caller's permissions and secrets, so every uses: it runs is a transitive supply-chain dependency of every consumer.
  • A JavaScript action ships a bundle nobody rebuilds, so the committed artifact — not the source — is what runs in production.
  • Untrusted workflow context (github.event.*, branch names, issue and PR text) reaches the action as ordinary input, so upstream secure-use guidance applies inside the action, not only in the consuming workflow.

Candidate rules

  • R-GHA-1: action.yml is complete and honest. name, description, author, branding, runs, and every input and output carry a description; each input declares required and, where optional, a default. Every input the code reads is declared, and every declared input is read.
  • R-GHA-2: The runtime is supported and pinned. runs.using names a Node major GitHub still supports, a composite runtime, or a Docker image pinned by digest. The action does not silently depend on a toolchain the runner happens to provide.
  • R-GHA-3: Documented examples request minimum permissions. Every README and example workflow sets an explicit permissions: block containing only the scopes the action needs, and the docs state which GITHUB_TOKEN scopes are required for which feature.
  • R-GHA-4: Inputs are validated before side effects. Inputs are parsed and range/format checked before filesystem writes, network calls, process execution, or API mutations. Untrusted workflow context is never interpolated into a shell string; argument arrays or library calls are used instead.
  • R-GHA-5: Secret inputs never reach logs, outputs, or artifacts. Token-shaped inputs are registered as masked at first use, are excluded from debug output and error messages, and are not written to step outputs, job summaries, uploaded artifacts, or committed files.
  • R-GHA-6: Bundled output matches source. A JavaScript action's committed bundle is reproducible from source with a pinned bundler, and CI fails when a clean rebuild produces a diff against the committed artifact.
  • R-GHA-7: Failure is signalled through the action protocol. Failures set a failed conclusion or exit non-zero; an action does not log an error and exit 0. Expected-failure outcomes, such as a quality gate below its threshold, are distinguishable in the log from unexpected runtime failures.
  • R-GHA-8: Release tags make consumer pinning reliable. Every release publishes an immutable vX.Y.Z tag. A floating major tag, if offered, is documented as moving, and the README shows SHA pinning as the option for privileged consumers.
  • R-GHA-9: Dependencies and nested actions are pinned and reviewed. A lockfile is committed, third-party uses: entries inside a composite action are pinned to a reviewed version or SHA per the action's stated policy, and dependency updates are reviewed before a release tag moves.
  • R-GHA-10: The action is smoke-tested the way a consumer runs it. CI runs the action from the repository in a real workflow job, over at least one success case and one expected failure case, and retains the run as evidence.

Severity and evidence

Severities follow the shared rule contract. Severity belongs to the rule, not to the reviewer.

Rules Severity Escalation
R-GHA-5 blocker Already top severity. A leaked token in a public run log is an incident, not a finding.
R-GHA-4 high blocker when an unvalidated input reaches a shell, exec, or an API write.
R-GHA-3, R-GHA-6, R-GHA-8, R-GHA-9 high blocker for R-GHA-9 when a privileged composite step is unpinned and the action is documented for use with contents: write or secrets.
R-GHA-7 high Stays high; a silent 0 on failure turns every consumer's quality gate into decoration.
R-GHA-1, R-GHA-2 medium high when an undeclared input carries a credential, or when the pinned runtime is out of GitHub support.
R-GHA-10 evidence-only high when the action performs a privileged mutation (comments, commits, releases, deployments) with no consumer-shaped run to prove it.

Required evidence:

evidence:
  configFiles:
    - "action.yml"
    - "package.json"
    - ".github/workflows/*.yml"
    - "Dockerfile"
  sourcePaths:
    - "src/**"
    - "dist/**"
  ciArtifacts:
    - "clean-rebuild diff job proving the committed bundle matches source"
    - "workflow run that invokes the action from this repository"
  runtimeProof:
    - "run log for one success case and one expected-failure case"
    - "step conclusion for the failure case, not just its log line"
  negativeEvidence:
    - "no secret input value present in the retained run log, outputs, or artifacts"
  exceptionFormat: "accepted-exception"

CI expectations: the rebuild-diff job and the consumer-shaped smoke job are required checks on the release path, not continue-on-error reporting jobs. A workflow that names a check but cannot fail the release is treated as absent, per the rule contract's anti-gaming section.

Exception policy

Exceptions use the acceptedException record in the rule contract: owner, scope, environment, reason, compensating controls, evidence, expiry, approval trail. Stack-specific rulings:

  • R-GHA-6 is exceptionable only for non-JavaScript actions. Composite and Docker actions have no bundle; record the runtime as the scope rather than claiming an exception.
  • R-GHA-8 is exceptionable for an internal action consumed only from the same organisation, with the consuming repositories named as the scope and a review date. It is not exceptionable for a public marketplace action.
  • R-GHA-9 may accept a reviewed floating major tag for first-party GitHub-published actions when the compensating control is a pinned lockfile plus a dependency review gate, recorded with an expiry.
  • R-GHA-5 is never exceptionable. No owner, expiry, or compensating control makes a leaked token acceptable; the finding is closed by rotating the credential and fixing the leak.
  • An exception cannot change the archetype. An action that requires the consumer to grant contents: write for a read-only feature is not a minimum-permission action with an exception; the feature set is wrong.

Anti-patterns

  • Documenting an example workflow with no permissions: block, leaving consumers on the default token scope.
  • Reading an environment variable or github.event field the action never declares as an input, so consumers cannot see what it consumes.
  • Interpolating ${{ github.event.issue.title }} — or any other attacker-controllable context — into a run: step inside a composite action.
  • Committing dist/ by hand after a local build, with no job that proves it matches source.
  • Echoing an API key into debug output "just for this release", in a public repository.
  • Catching every error, printing it, and exiting 0, so the consumer's gate always passes.
  • Publishing only a moving v1 tag and documenting it as if it were immutable.
  • Testing the action by unit-testing its helper functions and never once running it as a workflow step.
  • Pinning the action's own dependencies while calling an unpinned third-party action from inside a composite step that runs with the caller's token.

Promotion criteria

This charter can be cut as github-action-package/v1 when all of the following are true.

  1. Every candidate rule is rewritten in the rule-contract rule template, with severity, why, evidence, exception, a vcqa scanner or human-review signal, and a good/bad example.
  2. Each rule has been judged against a real action package at a named commit, with the pass/fail recorded, by something other than prose. ref-github-action-package maps every rule on this page to evidence at its assessed commit, but by hand in its report; R-GHA-8 in particular is documented rather than exercised, because no release tag has been cut. vibecodeqa/action is the only other in-house consumer and it is a composite action, so it cannot exercise the JavaScript-bundle rules on its own.
  3. ref-github-action-package exists and demonstrates the rules this charter claims are checkable, with score evidence in compositions.json (#44). Met — the repo is built and published in the catalog; see Reference implementation above. The 2026-07-25 assessment asked for this charter to be expanded before that repo was built; this page is that expansion.
  4. JavaScript, composite, and Docker expectations are separated at rule level rather than in prose.
  5. A fresh independent assessment scores this page above the draft band, replacing the dated report linked below.
  6. The registry entry gains a v1 edition with reviewed, next-review, targets, and lifecycle metadata, and the page is rewritten to the authored charter bar in Standards Authoring.

Review cadence

While this charter is a candidate rubric it is reviewed:

  • whenever GitHub changes supported action runtimes, metadata syntax, or default token permissions;
  • whenever vibecodeqa/action changes runtime, permission surface, or release policy;
  • whenever a reference implementation for this stack is created or scored;
  • and in any case no later than six months after the date of the most recent assessment report linked below.

Benefits

  • vibecodeqa/action is a public composite action that runs the VCQA CLI in a consumer's workflow, declares eight inputs and four outputs, and takes an anthropic-api-key secret input. It is the in-house repository this charter's metadata, permission, secret-input, and release-tag rules were written against.

Independent Assessment

That report is a dated snapshot: it scored this page on 2026-07-25, when it had no candidate rules, no upstream references, and no severity or exception policy, and it scored 25/100 for exactly those gaps. Its Required Fixes are what this page now implements. The score is not restated here as current, and the report is not rewritten — a re-assessment is a promotion criterion above.