diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 4894bab..0952f83 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -4,9 +4,7 @@ This repository contains reusable GitHub Actions workflows for the `datasciencec ## Repository purpose -- Use this repository only for workflows that require `datasciencecampus` organization-scoped credentials or policies. -- Prefer `ONSdigital/ons-github-actions` for broadly reusable workflows that do not depend on this org boundary. - +- Use this repository when a workflow needs `datasciencecampus` credentials or policies, or when public repositories must be able to call it. ## Security posture - Changes in this repository should follow secure-by-design principles. @@ -16,42 +14,49 @@ This repository contains reusable GitHub Actions workflows for the `datasciencec ## Workflow structure -- Public caller-facing workflows use the clean `add-*` names: +- Project-routing public caller-facing workflows use the clean `add-*` names: - `.github/workflows/add-issue-to-projects.yml` - `.github/workflows/add-pr-to-projects.yml` -- Internal privileged implementations use `*-impl` names: +- Other public reusable workflow entry points are: + - `.github/workflows/security-analysis.yml` (orchestrates zizmor and Checkov) + - `.github/workflows/terraform-quality.yml` +- Security-analysis child workflows are `.github/workflows/zizmor.yml` and `.github/workflows/checkov.yml`; callers should use the orchestrator so both tools share its trigger and policy configuration. +- Internal project-routing implementations use `*-impl` names: - `.github/workflows/add-issue-to-projects-impl.yml` - `.github/workflows/add-pr-to-projects-impl.yml` -- Reusable workflow tests use `*-reusable` names: +- Reusable workflow tests use `test-*-reusable` names: - `.github/workflows/test-add-issue-to-projects-reusable.yml` - `.github/workflows/test-add-pr-to-projects-reusable.yml` + - `.github/workflows/test-terraform-quality-reusable.yml` -Do not collapse the public and internal workflows back into one file unless the user explicitly asks for that architectural change. +Do not collapse the project-routing public and internal workflows back into one file unless the user explicitly asks for that architectural change. ## Public contract conventions -- The public `add-*` workflows are the API that other repositories consume via `uses:`. -- The internal `*-impl` workflows are dispatch-only and should not be documented as the primary caller entrypoint. -- If caller-facing inputs change, update all of these together: +- The public `add-*` workflows are the caller API for project routing. The internal `*-impl` workflows are dispatch-only and should not be documented as the caller entrypoint. +- `security-analysis.yml` and `terraform-quality.yml` are public `workflow_call` entry points. Their inputs and permission requirements belong in the reusable-workflow reference and their relevant how-to guides. +- If a caller-facing contract changes, update the relevant items together: - `README.md` - `docs/reference/reusable-workflows.md` - relevant `docs/how-to/*.md` -- If the change is architectural rather than cosmetic, add or update an ADR under `docs/explanation/`. + - `docs/how-to/README.md` or `docs/README.md` when pages or navigation change +- If the change is architectural rather than cosmetic, add or update an ADR under `docs/explanation/adr/` and link it from `docs/explanation/adr/README.md`. ## Pinning and dispatch gotchas +- These dispatch and `implementation_ref` rules apply to the project-routing workflows, not to security-analysis or terraform-quality. - `workflow_dispatch` requires a branch or tag ref, not a raw commit SHA. -- Public reusable workflows support SHA pinning at the `uses:` boundary, but internal dispatch still needs a branch or tag ref. -- If `implementation_ref` is omitted, the public reusable workflow first uses `github.workflow_ref` when that is already a branch or tag. -- For SHA-pinned callers, the public reusable workflow reads `configs/implementation-ref.json` from the pinned workflow revision, takes `implementation_version`, and dispatches the matching `v...` tag. -- For pull request contexts, do not dispatch on `refs/pull/*/merge`; use the PR head branch. +- Project-routing public reusable workflows support SHA pinning at the `uses:` boundary, but their internal dispatch still needs a branch or tag ref. +- If `implementation_ref` is omitted, the project-routing workflow first uses `github.workflow_ref` when that is already a branch or tag. +- For SHA-pinned project-routing callers, the public workflow reads `configs/implementation-ref.json` from the pinned workflow revision, takes `implementation_version`, and dispatches the matching `v...` tag. +- For project-routing pull request contexts, do not dispatch on `refs/pull/*/merge`; use the PR head branch. ## Secrets and credentials -- Caller-side router credentials: +- Caller-side router credentials are used only by project-routing workflows: - `PROJECT_ROUTER_BOT_APP_ID` - `PROJECT_ROUTER_BOT_PRIVATE_KEY` -- Internal implementation credentials: +- Internal implementation credentials are used only by project-routing implementations: - `PROJECT_HANDLER_BOT_APP_ID` - `PROJECT_HANDLER_BOT_PRIVATE_KEY` - Do not use `secrets: inherit` for this workflow family unless the user explicitly requests it. @@ -59,11 +64,12 @@ Do not collapse the public and internal workflows back into one file unless the - Keep credential use inside the narrowest possible workflow boundary. - Do not broaden GitHub token or app permissions without a clear repository-specific reason. - Validate repository ownership, organization scope, and object provenance before mutating projects or dispatching privileged workflows. +- Security-analysis callers should grant only `actions: read`, `contents: read`, and `security-events: write` to the reusable-workflow job. Terraform-quality callers need only `contents: read`. Prefer `permissions: {}` at workflow level and explicit job-level grants. ## Release Please conventions - Release automation is managed by `.github/workflows/release-please.yml` and `release-please-config.json`. -- `configs/implementation-ref.json` stores the release-managed `implementation_version` used for SHA-pinned dispatch resolution. +- `configs/implementation-ref.json` stores the release-managed `implementation_version` used for project-routing SHA-pinned dispatch resolution. - Release Please updates `configs/implementation-ref.json` via the JSON updater; workflows prepend `v` when dispatching. - Internal test workflows use local reusable workflow paths and should not be version-pinned or wired into release-please version bumping. @@ -71,6 +77,7 @@ Do not collapse the public and internal workflows back into one file unless the - Keep docs concise and task-oriented. - Use `docs/how-to/` for usage steps, `docs/reference/` for exact contracts, and `docs/explanation/` for rationale. +- Use the category index pages in `docs/README.md` to navigate to lower-level indexes. Put ADRs in `docs/explanation/adr/` and maintain that folder's `README.md` index. - When examples show consumer workflows, prefer `@` without `implementation_ref` unless the example is explicitly showing an override. ## Change discipline diff --git a/README.md b/README.md index 07a023d..5d11f6a 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,14 @@ This repository contains workflows that depend on `datasciencecampus` organizati ## Overview -This repository currently provides three public reusable workflows: +This repository currently provides four public reusable workflows: - `add-issue-to-projects`: add new issues to one or more `datasciencecampus` ProjectsV2 boards. - `add-pr-to-projects`: add new pull requests to one or more `datasciencecampus` ProjectsV2 boards and set configured field values. - `security-analysis`: scan GitHub Actions workflows and infrastructure-as-code for security issues using zizmor and checkov. +- `terraform-quality`: check Terraform formatting, validate configuration, and run TFLint. -Each public reusable workflow has a matching internal implementation workflow. The public workflow is the caller-facing contract; the internal workflow owns the privileged `workflow_dispatch` path and project mutation logic. +The project workflows each have a matching internal implementation workflow. Their public workflows are the caller-facing contracts; the internal workflows own the privileged `workflow_dispatch` path and project mutation logic. ## Workflow Catalog @@ -25,6 +26,13 @@ Orchestrates GitHub Actions security analysis with `zizmor` and infrastructure s - Child workflow (checkov): [.github/workflows/checkov.yml](.github/workflows/checkov.yml) - How-to guide: [docs/how-to/use-security-analysis-workflow.md](docs/how-to/use-security-analysis-workflow.md) +### `terraform-quality` + +Checks Terraform configuration with `terraform fmt`, `terraform validate`, and TFLint. Callers can select validation directories and Terraform version, and enable or disable each check. + +- Reusable workflow: [.github/workflows/terraform-quality.yml](.github/workflows/terraform-quality.yml) +- How-to guide: [docs/how-to/use-terraform-quality-workflow.md](docs/how-to/use-terraform-quality-workflow.md) + ### `add-issue-to-projects` Adds opened issues to one or more `datasciencecampus` Projects by project number, with optional field updates. @@ -47,8 +55,8 @@ Adds opened pull requests to `datasciencecampus` Projects and sets configured fi Consumers should call the public reusable workflows from other repositories using `uses:`. -- By default, the reusable workflows dispatch the release tag recorded in metadata stored alongside the invoked workflow revision. -- Set `implementation_ref` only when you need to override that release-managed dispatch target with a specific branch or tag. +- The `add-issue-to-projects` and `add-pr-to-projects` workflows dispatch the release tag recorded in metadata alongside the invoked workflow revision by default. +- Set `implementation_ref` on either project workflow only when you need to override that release-managed dispatch target with a specific branch or tag. > [!IMPORTANT] > Public repositories that trigger these workflows automatically from issue or pull request creation events must restrict those events to trusted actors, for example by allowing only collaborators to open issues or pull requests. Configure this in the caller repository at `https://github.com///settings` under `Settings > General > Features`, then use `Issues > Issue permissions` or `Pull requests > Pull request permissions` as appropriate. diff --git a/docs/README.md b/docs/README.md index 994e39c..87e3f90 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,26 +1,13 @@ -# Documentation (Diataxis) +# Documentation -Keep docs short and practical. +Browse by what you need to do or understand: -## Structure +The documentation is organized using the [Diataxis framework](https://diataxis.fr/). -- `docs/tutorials/`: learning by doing -- `docs/how-to/`: task steps -- `docs/reference/`: facts, inputs, outputs -- `docs/explanation/`: rationale and trade-offs +## Browse documentation -## Pages +- [How-to guides](how-to/README.md) — Follow steps to use the reusable workflows. +- [Reference](reference/README.md) — Look up workflow contracts, inputs, permissions, and GitHub Apps. +- [Explanations](explanation/README.md) — Understand the architecture, trust boundaries, and design decisions. +- [Tutorials](tutorials/README.md) — Learn through guided examples; no tutorials are published yet. -- How-to: - - `docs/how-to/use-add-issue-to-projects-workflow.md` - - `docs/how-to/use-add-pr-to-projects-workflow.md` -- Reference: - - `docs/reference/reusable-workflows.md` -- Explanation: - - `docs/explanation/README.md` - -## Rules - -- Put all docs under `docs/`. -- Pick one category per page. -- Prefer concise examples over long prose. diff --git a/docs/explanation/README.md b/docs/explanation/README.md index 7c98755..e2604b1 100644 --- a/docs/explanation/README.md +++ b/docs/explanation/README.md @@ -6,10 +6,6 @@ Background, rationale, and trade-offs. - [Workflow trust boundaries](workflow-trust-boundaries.md) -## ADRs +## Architecture Decision Records -- [ADR-0001: Called workflow owns secret usage](ADR-0001-called-workflow-owns-secret-usage.md) -- [ADR-0002: Use workflow_dispatch instead of repository_dispatch](ADR-0002-workflow-dispatch-over-repository-dispatch.md) -- [ADR-0003: Unified project_field_values input with optional field updates](ADR-0003-unified-project-field-values-input.md) -- [ADR-0004: Separate reusable workflow pinning from dispatch ref](ADR-0004-separate-reusable-pinning-from-dispatch-ref.md) -- [ADR-0005: Security workflow orchestration pattern](ADR-0005-security-workflow-orchestration.md) +- [Browse architecture decision records](adr/README.md) diff --git a/docs/explanation/ADR-0001-called-workflow-owns-secret-usage.md b/docs/explanation/adr/ADR-0001-called-workflow-owns-secret-usage.md similarity index 100% rename from docs/explanation/ADR-0001-called-workflow-owns-secret-usage.md rename to docs/explanation/adr/ADR-0001-called-workflow-owns-secret-usage.md diff --git a/docs/explanation/ADR-0002-workflow-dispatch-over-repository-dispatch.md b/docs/explanation/adr/ADR-0002-workflow-dispatch-over-repository-dispatch.md similarity index 100% rename from docs/explanation/ADR-0002-workflow-dispatch-over-repository-dispatch.md rename to docs/explanation/adr/ADR-0002-workflow-dispatch-over-repository-dispatch.md diff --git a/docs/explanation/ADR-0003-unified-project-field-values-input.md b/docs/explanation/adr/ADR-0003-unified-project-field-values-input.md similarity index 100% rename from docs/explanation/ADR-0003-unified-project-field-values-input.md rename to docs/explanation/adr/ADR-0003-unified-project-field-values-input.md diff --git a/docs/explanation/ADR-0004-separate-reusable-pinning-from-dispatch-ref.md b/docs/explanation/adr/ADR-0004-separate-reusable-pinning-from-dispatch-ref.md similarity index 98% rename from docs/explanation/ADR-0004-separate-reusable-pinning-from-dispatch-ref.md rename to docs/explanation/adr/ADR-0004-separate-reusable-pinning-from-dispatch-ref.md index 5ec0765..bf1131f 100644 --- a/docs/explanation/ADR-0004-separate-reusable-pinning-from-dispatch-ref.md +++ b/docs/explanation/adr/ADR-0004-separate-reusable-pinning-from-dispatch-ref.md @@ -54,7 +54,7 @@ jobs: with: repository: ${{ github.event.repository.name }} issue_node_id: ${{ github.event.issue.node_id }} - project_field_values: '[{"project":1234}]' + project_field_values: '[{"project":1234}]' ``` ## Rationale diff --git a/docs/explanation/ADR-0005-security-workflow-orchestration.md b/docs/explanation/adr/ADR-0005-security-workflow-orchestration.md similarity index 83% rename from docs/explanation/ADR-0005-security-workflow-orchestration.md rename to docs/explanation/adr/ADR-0005-security-workflow-orchestration.md index 7849819..60a3da6 100644 --- a/docs/explanation/ADR-0005-security-workflow-orchestration.md +++ b/docs/explanation/adr/ADR-0005-security-workflow-orchestration.md @@ -36,7 +36,7 @@ Create a single orchestrator workflow (`security-analysis.yml`) that runs on `pu - Caller customization via workflow_call inputs (config paths, persona, advanced-security override) 5. **Clear caller contract** - Repositories should call `security-analysis.yml`, not individual tool workflows. This prevents confusion about which workflow to use and ensures both tools always run together. + Repositories should call `security-analysis.yml`, not individual tool workflows. This prevents confusion about which workflow to use and runs both tools together through the supported entry point. 6. **Parallel execution** Both tools run in parallel, reducing overall workflow runtime compared to sequential execution. @@ -46,15 +46,15 @@ Create a single orchestrator workflow (`security-analysis.yml`) that runs on `pu Positive: - Simpler mental model for repository maintainers (one workflow to add, not two) -- Guaranteed consistency: both tools always run together +- Consistent results when callers use the orchestrator: both tools run together - Easier to update default behavior organization-wide (one place to change) -- Enforces "security by default" — repositories can't accidentally skip one tool +- Provides one recommended entry point that includes both tools - Flexible customization for specific repositories via workflow_call Negative: - If one tool needs to run independently, we'd need to refactor the architecture -- Child workflows cannot be called directly (only via orchestrator), which limits flexibility +- Child workflows expose `workflow_call` and can be called directly, but direct calls bypass the orchestrator's shared triggers, concurrency, and combined-results contract - Orchestrator adds one layer of indirection (minimal performance impact) ## Alternatives considered @@ -68,7 +68,7 @@ Negative: - Con: Composite actions don't support workflow triggers or SARIF uploads 3. **Orchestrator + direct child calls** - - Current decision; child workflows are reusable-only to prevent independent runs + - Current decision; child workflows expose only `workflow_call`. Callers should use the orchestrator to run both tools together, although GitHub does not prevent direct calls to an individual child workflow. ## Related decisions diff --git a/docs/explanation/adr/README.md b/docs/explanation/adr/README.md new file mode 100644 index 0000000..e7033c0 --- /dev/null +++ b/docs/explanation/adr/README.md @@ -0,0 +1,9 @@ +# Architecture Decision Records + +Decisions that document the rationale and trade-offs behind the repository's workflow architecture. + +- [ADR-0001: Called workflow owns secret usage](ADR-0001-called-workflow-owns-secret-usage.md) +- [ADR-0002: Use workflow_dispatch instead of repository_dispatch](ADR-0002-workflow-dispatch-over-repository-dispatch.md) +- [ADR-0003: Unified project_field_values input with optional field updates](ADR-0003-unified-project-field-values-input.md) +- [ADR-0004: Separate reusable workflow pinning from dispatch ref](ADR-0004-separate-reusable-pinning-from-dispatch-ref.md) +- [ADR-0005: Security workflow orchestration pattern](ADR-0005-security-workflow-orchestration.md) \ No newline at end of file diff --git a/docs/explanation/workflow-trust-boundaries.md b/docs/explanation/workflow-trust-boundaries.md index d8e1290..9197261 100644 --- a/docs/explanation/workflow-trust-boundaries.md +++ b/docs/explanation/workflow-trust-boundaries.md @@ -97,7 +97,7 @@ flowchart LR Related references: -- [ADR-0001: Called workflow owns secret usage](ADR-0001-called-workflow-owns-secret-usage.md) -- [ADR-0002: Use workflow_dispatch instead of repository_dispatch](ADR-0002-workflow-dispatch-over-repository-dispatch.md) -- [ADR-0004: Separate reusable workflow pinning from dispatch ref](ADR-0004-separate-reusable-pinning-from-dispatch-ref.md) +- [ADR-0001: Called workflow owns secret usage](adr/ADR-0001-called-workflow-owns-secret-usage.md) +- [ADR-0002: Use workflow_dispatch instead of repository_dispatch](adr/ADR-0002-workflow-dispatch-over-repository-dispatch.md) +- [ADR-0004: Separate reusable workflow pinning from dispatch ref](adr/ADR-0004-separate-reusable-pinning-from-dispatch-ref.md) - [GitHub Apps reference](../reference/github-apps.md) diff --git a/docs/how-to/README.md b/docs/how-to/README.md index 2336d70..ff0f834 100644 --- a/docs/how-to/README.md +++ b/docs/how-to/README.md @@ -7,3 +7,4 @@ Task-focused instructions. - [Use the add-issue-to-projects reusable workflow](use-add-issue-to-projects-workflow.md) - [Use the add-pr-to-projects reusable workflow](use-add-pr-to-projects-workflow.md) - [Use the security-analysis reusable workflow](use-security-analysis-workflow.md) +- [Use the terraform-quality reusable workflow](use-terraform-quality-workflow.md) diff --git a/docs/how-to/use-security-analysis-workflow.md b/docs/how-to/use-security-analysis-workflow.md index e602a3a..08c58a4 100644 --- a/docs/how-to/use-security-analysis-workflow.md +++ b/docs/how-to/use-security-analysis-workflow.md @@ -25,7 +25,7 @@ Add a security analysis workflow to your repository's `.github/workflows/` direc ### Option 1: Default configuration -Use organization defaults (zizmor persona: `auditor`, all checks enabled): +Use the default settings (zizmor persona: `auditor`, both tools enabled): ```yaml name: Security Analysis @@ -36,11 +36,26 @@ on: pull_request: branches: [main] +run-name: "${{ github.workflow }} - ${{ github.actor }} - ${{ github.event_name == 'pull_request' && format('PR #{0}', github.event.pull_request.number) || github.ref_name }}" + +permissions: {} # Deny token access by default; jobs grant only what they need. + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + jobs: security-analysis: + name: security-analysis + permissions: + actions: read # Required for SARIF upload metadata lookups in private or internal repositories. + contents: read # Required to read repository contents during analysis. + security-events: write # Required to upload security analysis results. uses: datasciencecampus/github-actions/.github/workflows/security-analysis.yml@ ``` +The top-level `permissions: {}` denies `GITHUB_TOKEN` access by default. The reusable-workflow job then grants only the permissions the analysis needs: `actions: read` for SARIF metadata lookups, `contents: read` to scan repository content, and `security-events: write` to upload SARIF results. Use the same permission declarations with the custom configuration below. + ### Option 2: Custom configuration To customize config paths, persona, or advanced-security behavior: @@ -54,8 +69,15 @@ on: pull_request: branches: [main] +permissions: {} # Deny token access by default; jobs grant only what they need. + jobs: security-analysis: + name: security-analysis + permissions: + actions: read # Required for SARIF upload metadata lookups in private or internal repositories. + contents: read # Required to read repository contents during analysis. + security-events: write # Required to upload security analysis results. uses: datasciencecampus/github-actions/.github/workflows/security-analysis.yml@ with: zizmor-config: ./config/zizmor-custom.yaml @@ -66,14 +88,14 @@ jobs: ## Configuration -### Organization config files +### Config files -Both tools use organization-managed default config files: +The default config paths are relative to the calling repository's checkout: -- **zizmor**: `datasciencecampus/github-actions:./configs/zizmor.yaml` -- **checkov**: `datasciencecampus/github-actions:./configs/checkov.yml` +- **zizmor**: `./configs/zizmor.yaml` +- **checkov**: `./configs/checkov.yml` -To customize, create your own config files in your repository and reference them via `zizmor-config` and `checkov-config` inputs. +This repository contains these files for its own push and pull-request runs. When calling the reusable workflow from another repository, provide the files at these paths or set `zizmor-config` and `checkov-config` to config files in the caller's repository. The called workflow does not fetch config files from this repository. ### zizmor personas @@ -145,8 +167,15 @@ on: - auditor default: auditor +permissions: {} # Deny token access by default; jobs grant only what they need. + jobs: security-analysis: + name: security-analysis + permissions: + actions: read # Required for SARIF upload metadata lookups in private or internal repositories. + contents: read # Required to read repository contents during analysis. + security-events: write # Required to upload security analysis results. uses: datasciencecampus/github-actions/.github/workflows/security-analysis.yml@ with: zizmor-persona: ${{ github.event.inputs.zizmor-persona || 'auditor' }} diff --git a/docs/how-to/use-terraform-quality-workflow.md b/docs/how-to/use-terraform-quality-workflow.md new file mode 100644 index 0000000..8ae41e7 --- /dev/null +++ b/docs/how-to/use-terraform-quality-workflow.md @@ -0,0 +1,60 @@ +# Use terraform-quality + +Run Terraform formatting checks, validation, and TFLint analysis with the reusable workflow. + +Reusable workflow: `.github/workflows/terraform-quality.yml` + +## Prerequisites + +- Terraform configuration must be under the caller repository's `terraform/` directory. +- When TFLint is enabled, the caller repository must include `configs/.tflint.hcl`. +- No secrets are required. The workflow needs `contents: read` to check out and validate the caller's repository. + +## Add to your repository + +Create `.github/workflows/terraform-quality.yml` in your repository: + +```yaml +name: Terraform Quality + +on: + push: + pull_request: + branches: ["main"] + +run-name: "${{ github.workflow }} - ${{ github.actor }} - ${{ github.event_name == 'pull_request' && format('PR #{0}', github.event.pull_request.number) || github.ref_name }}" + +permissions: {} # Deny token access by default; jobs grant only what they need. + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + terraform-quality: + name: terraform-quality + uses: datasciencecampus/github-actions/.github/workflows/terraform-quality.yml@caf4ab7c789a34efb07d61113830bcb67d634a38 # v1.7.0 + permissions: + contents: read # Required to check out and validate Terraform configuration. + with: + terraform-dirs: '["terraform/01_sandbox", "terraform/02_dev_nonprod", "terraform/03_stg_prod", "terraform/04_prd_prod", "terraform/modules"]' + terraform-version: "1.16.4" # This should match the terraform version used in the repo. + run-fmt: true + run-validate: true + run-tflint: true +``` + +The top-level `permissions: {}` denies token access by default. The reusable-workflow job grants only `contents: read`; Terraform quality checks do not need the `security-events: write` or `actions: read` permissions used by the security-analysis workflow. + +## Inputs and check scope + +- `terraform-dirs`: JSON array of repository-relative Terraform directories to validate. The workflow validates the JSON and rejects empty, absolute, or traversal paths. By default, it validates the four standard environment directories. +- `terraform-version`: Terraform version to install. The workflow default is `1.14.3`; the example pins `1.16.4` explicitly. +- `run-fmt`, `run-validate`, and `run-tflint`: Enable or skip each check. All default to `true`. +- `continue_on_error`: Optional test input, default `false`. When enabled, validation check failures do not fail the workflow; input validation errors still prevent the checks from running. + +`terraform-dirs` selects directories for `terraform validate`. The format check and TFLint currently scan the `terraform/` directory recursively, regardless of this input. + +## Results + +Each check runs as a separate job in the Actions workflow. A failed enabled check fails the caller's workflow run; disabled checks are skipped. \ No newline at end of file diff --git a/docs/reference/github-apps.md b/docs/reference/github-apps.md index 9338468..c7a80de 100644 --- a/docs/reference/github-apps.md +++ b/docs/reference/github-apps.md @@ -18,7 +18,7 @@ This repository uses two GitHub Apps with distinct responsibilities and permissi The `actions: write` permission is the minimum required to call `POST /repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches` (the `workflow_dispatch` trigger endpoint). See -[ADR-0002](../explanation/ADR-0002-workflow-dispatch-over-repository-dispatch.md) +[ADR-0002](../explanation/adr/ADR-0002-workflow-dispatch-over-repository-dispatch.md) for why `workflow_dispatch` was chosen over `repository_dispatch`. **Used in:** caller workflows in approved repositories that are provisioned for this integration (see how-to guides). diff --git a/docs/reference/reusable-workflows.md b/docs/reference/reusable-workflows.md index 2c3f7aa..ca70cc1 100644 --- a/docs/reference/reusable-workflows.md +++ b/docs/reference/reusable-workflows.md @@ -2,9 +2,9 @@ This page lists the workflows in this repository and their caller-facing contracts. -## Shared credential model +## Project workflow credentials -Authorized callers use the dispatch credentials to trigger workflows: +Callers of the project-routing workflows use these credentials to dispatch the internal implementations: - `PROJECT_ROUTER_BOT_APP_ID` (Actions variable, org-level) - `PROJECT_ROUTER_BOT_PRIVATE_KEY` (Actions secret, org-level) @@ -12,7 +12,7 @@ Authorized callers use the dispatch credentials to trigger workflows: > [!IMPORTANT] > For public caller repositories that run these workflows automatically on issue or pull request creation events, those events must be limited to trusted actors. In practice, require collaborator-only issue or pull request creation, or an equivalent repository control. Configure this in the caller repository at `https://github.com///settings` under `Settings > General > Features`, then use `Issues > Issue permissions` or `Pull requests > Pull request permissions` as appropriate. -Project-handling credentials are used internally and are not required from callers. The called workflows verify that the requested organization matches this repository owner and that the submitted issue or pull request node ID resolves back to the repository named in the request. See [GitHub Apps reference](github-apps.md). +Project-handling credentials are used internally and are not required from callers. The project workflows verify that the requested organization matches this repository owner and that the submitted issue or pull request node ID resolves back to the repository named in the request. See [GitHub Apps reference](github-apps.md). ## add-issue-to-projects @@ -173,9 +173,9 @@ Orchestrates GitHub Actions security analysis with `zizmor` and infrastructure s ### Security Analysis Call Inputs (workflow_call only) -- `zizmor-config`: optional string. Path to zizmor config file. Defaults to `./configs/zizmor.yaml`. +- `zizmor-config`: optional string. Path to zizmor config file in the caller's checkout. Defaults to `./configs/zizmor.yaml`. - `zizmor-persona`: optional string. Persona for zizmor analysis: `regular`, `pedantic`, or `auditor`. Defaults to `auditor`. -- `checkov-config`: optional string. Path to checkov config file. Defaults to `./configs/checkov.yml`. +- `checkov-config`: optional string. Path to checkov config file in the caller's checkout. Defaults to `./configs/checkov.yml`. - `advanced-security`: optional boolean. Upload SARIF results to GitHub Advanced Security. Tri-state behavior: - Omitted (default): Auto-detect based on repository privacy (true for public, false for private) - `true`: Always upload @@ -186,15 +186,49 @@ Orchestrates GitHub Actions security analysis with `zizmor` and infrastructure s 1. Runs `zizmor` to scan GitHub Actions workflows for security misconfigurations. 2. Runs `checkov` to scan infrastructure-as-code and configuration files. 3. Both tools run in parallel and upload SARIF results to GitHub Advanced Security (when enabled). -4. Uses organization-managed config defaults from `./configs/zizmor.yaml` and `./configs/checkov.yml`. +4. Reads config files from the caller's checkout at the configured paths. ### Security Analysis Notes -- **Default triggers**: On `push` and `pull_request` to `main`, uses organization defaults (zizmor persona: `auditor`, both tools enabled). +- **Default triggers**: On this repository's `push` and `pull_request` events for `main`, the config files in this repository are used (zizmor persona: `auditor`, both tools enabled). Callers using `workflow_call` must provide the config files in their own checkout or set the config path inputs. - **Customization**: Callers can override config paths, persona, and advanced-security via `workflow_call` inputs. - **Tri-state logic**: `advanced-security` input is tri-state (omit = auto-detect, true = enable, false = disable). This logic is computed by the orchestrator and passed to child workflows. - **Concurrency**: Managed at the orchestrator level to prevent duplicate runs. -- **Child workflows**: `zizmor.yml` and `checkov.yml` are internal workflows and should be called only via `security-analysis.yml`. +- **Child workflows**: `zizmor.yml` and `checkov.yml` expose `workflow_call` and can be called directly, but callers should use `security-analysis.yml` to run both tools with the shared trigger, concurrency, and SARIF policy. + +## terraform-quality + +Workflow file: `.github/workflows/terraform-quality.yml` + +### Terraform Quality Trigger + +`workflow_call` only. + +### Terraform Quality Inputs + +- `terraform-dirs`: optional JSON array of repository-relative directories to validate. Defaults to the four standard environment directories. Input validation rejects non-arrays, non-string entries, empty paths, absolute paths, and paths containing `..`. +- `terraform-version`: optional string. Terraform version to install. Defaults to `1.14.3`. +- `run-fmt`: optional boolean. Run the Terraform formatting check. Defaults to `true`. +- `run-validate`: optional boolean. Run `terraform init -backend=false` and `terraform validate` for each configured directory. Defaults to `true`. +- `run-tflint`: optional boolean. Run TFLint. Defaults to `true`. +- `continue_on_error`: optional boolean intended for negative testing. Defaults to `false`; when enabled, failures in the validation checks do not fail the workflow. + +### Terraform Quality Behavior + +1. Validates the `terraform-dirs` input before running checks. +2. Runs `terraform fmt -check -recursive terraform` when formatting is enabled. +3. Runs `terraform init -backend=false` and `terraform validate` for each configured directory when validation is enabled. +4. Runs TFLint recursively under `terraform/` when enabled, using `configs/.tflint.hcl` from the caller's checkout. + +### Terraform Quality Notes + +- `terraform-dirs` controls only `terraform validate`; formatting and TFLint scan the entire `terraform/` directory. +- The caller must provide `configs/.tflint.hcl` when TFLint is enabled. +- The workflow exposes a `validation-passed` output indicating whether `terraform-dirs` input validation succeeded. + +### Terraform Quality `GITHUB_TOKEN` Permissions + +- `contents: read` ## zizmor