← Files SSOT CheckARCHIVED FILE

action.yml

3.11 KB · Oct 2, 2026 · 00:33 UTC

↓ Download file

name: "ssot-check"
description: "Audit single-source-of-truth drift: verify every hand-copied fact still matches its canonical value."
branding:
  icon: "check-circle"
  color: "blue"

inputs:
  manifest:
    description: "Path to the .ssot.yaml manifest."
    required: false
    default: ".ssot.yaml"
  root:
    description: "Repo root for resolving relative paths (default: manifest directory)."
    required: false
    default: ""
  fetch:
    description: >-
      For cross-repo copies, run `git fetch` in the sibling repo and compare
      against its remote-tracking ref. Makes a network call and updates that
      repo's remote-tracking refs and FETCH_HEAD; never pulls, rebases, or
      touches its working tree.
    required: false
    default: "false"
  json:
    description: "Emit machine-readable JSON instead of the text report."
    required: false
    default: "false"
  discover:
    description: >-
      Optional manifest-aware discovery after a successful check. Set to
      `warn` to annotate repeated facts and live-drift candidates that are not
      covered by the manifest; `off` disables it. Discovery is heuristic and
      never fails the step.
    required: false
    default: "off"

runs:
  using: "composite"
  steps:
    # Checkout is assumed to have run already in the calling workflow.
    - name: Run ssot-check
      shell: bash
      env:
        SSOT_INPUT_MANIFEST: ${{ inputs.manifest }}
        SSOT_INPUT_ROOT: ${{ inputs.root }}
        SSOT_INPUT_FETCH: ${{ inputs.fetch }}
        SSOT_INPUT_JSON: ${{ inputs.json }}
        SSOT_INPUT_DISCOVER: ${{ inputs.discover }}
      run: |
        CLI="${GITHUB_ACTION_PATH}/ssot_check.py"

        # Validate inputs before the check runs, so a typo fails immediately
        # instead of after a full audit. Normalize case and the boolean-ish
        # spellings a workflow's YAML may hand us for an unquoted `off`.
        DISCOVER="${SSOT_INPUT_DISCOVER,,}"
        case "$DISCOVER" in
          ""|off|false) DISCOVER=off ;;
          warn|true)    DISCOVER=warn ;;
          *)
            echo "Invalid discover input: expected 'off' or 'warn'." >&2
            exit 2
            ;;
        esac

        ARGS=(check --manifest "$SSOT_INPUT_MANIFEST")
        if [ -n "$SSOT_INPUT_ROOT" ]; then ARGS+=(--root "$SSOT_INPUT_ROOT"); fi
        if [ "$SSOT_INPUT_FETCH" = "true" ]; then ARGS+=(--fetch); fi
        if [ "$SSOT_INPUT_JSON" = "true" ]; then ARGS+=(--json); fi
        echo "Running: python3 ssot_check.py ${ARGS[*]}"
        python3 "$CLI" "${ARGS[@]}"
        # ssot_check.py exits 1 on drift and 2 on manifest error; either fails
        # the step (and the build) because bash propagates the exit code.

        if [ "$DISCOVER" = "warn" ]; then
          DISCOVER_ARGS=(
            discover
            --manifest "$SSOT_INPUT_MANIFEST"
            --untracked-only
            --github-annotations
          )
          if [ -n "$SSOT_INPUT_ROOT" ]; then
            DISCOVER_ARGS+=(--root "$SSOT_INPUT_ROOT")
          fi
          python3 "$CLI" "${DISCOVER_ARGS[@]}"
        fi

SHA-256: 05f415654dea6e638b218fb07cc3b0ddf2581ca9280c0a9be16562ef9336a662