systemd-resolved-rs 0.2.0

A compatibility-oriented reimplementation of systemd-resolved
name: Replacement security proof
run-name: Replacement security proof ${{ inputs.source_sha || github.sha }}

on:
  workflow_dispatch:
    inputs:
      source_sha:
        description: Full Git commit to prove; blank selects the dispatch ref
        required: false
        type: string

permissions:
  actions: read
  contents: read
  statuses: write

jobs:
  prove:
    runs-on: ubuntu-24.04
    timeout-minutes: 20
    steps:
      - name: Check out exact source
        uses: actions/checkout@v4
        with:
          ref: ${{ inputs.source_sha || github.sha }}
          fetch-depth: 1

      - name: Verify exact source identity
        shell: bash
        env:
          REQUESTED_SHA: ${{ inputs.source_sha || github.sha }}
        run: |
          set -euo pipefail
          [[ $REQUESTED_SHA =~ ^[0-9a-f]{40}$ ]]
          test "$(git rev-parse HEAD)" = "$REQUESTED_SHA"

      - name: Collect successful security evidence for this SHA
        shell: bash
        env:
          GH_TOKEN: ${{ github.token }}
          SOURCE_SHA: ${{ inputs.source_sha || github.sha }}
        run: |
          set -euo pipefail
          python3 - <<'PY'
          from __future__ import annotations

          import json
          import os
          from pathlib import Path
          import re
          import urllib.request

          repository = os.environ["GITHUB_REPOSITORY"]
          sha = os.environ["SOURCE_SHA"]
          token = os.environ["GH_TOKEN"]
          api = os.environ["GITHUB_API_URL"]

          def request(path: str) -> dict:
              req = urllib.request.Request(
                  api + path,
                  headers={
                      "Accept": "application/vnd.github+json",
                      "Authorization": f"Bearer {token}",
                      "X-GitHub-Api-Version": "2022-11-28",
                  },
              )
              with urllib.request.urlopen(req, timeout=30) as response:
                  return json.load(response)

          status_payload = request(
              f"/repos/{repository}/commits/{sha}/status"
          )
          security_status = next(
              (
                  item
                  for item in status_payload.get("statuses", [])
                  if item.get("context") == "replacement/security"
              ),
              None,
          )
          if not isinstance(security_status, dict) or security_status.get("state") != "success":
              raise SystemExit("replacement/security is not successful for this exact source SHA")
          target_url = security_status.get("target_url")
          if not isinstance(target_url, str):
              raise SystemExit("replacement/security has no workflow target URL")
          match = re.search(r"/actions/runs/(\d+)$", target_url)
          if not match:
              raise SystemExit("replacement/security target URL has no workflow run id")
          run_id = int(match.group(1))
          run = request(f"/repos/{repository}/actions/runs/{run_id}")
          if run.get("conclusion") != "success":
              raise SystemExit("the source-bound replacement/security workflow did not pass")
          jobs = request(
              f"/repos/{repository}/actions/runs/{run_id}/jobs?filter=latest&per_page=100"
          ).get("jobs", [])
          evidence = []
          for job in jobs:
              if job.get("conclusion") != "success":
                  continue
              successful_steps = [
                  step.get("name", "")
                  for step in job.get("steps", [])
                  if step.get("conclusion") == "success"
              ]
              evidence.append(
                  {
                      "workflow_id": run["workflow_id"],
                      "workflow_name": "Replacement security gates",
                      "workflow_display_name": run["name"],
                      "run_id": run["id"],
                      "run_attempt": run.get("run_attempt"),
                      "html_url": run["html_url"],
                      "event": run["event"],
                      "head_sha": sha,
                      "workflow_head_sha": run["head_sha"],
                      "created_at": run["created_at"],
                      "updated_at": run["updated_at"],
                      "job_id": job["id"],
                      "job_name": job["name"],
                      "steps": successful_steps,
                  }
              )

          categories = {
              "fuzz": re.compile(r"fuzz|libfuzzer", re.I),
              "asan": re.compile(r"address sanitizer|asan", re.I),
              "ubsan": re.compile(r"undefined behavior sanitizer|ubsan", re.I),
              "miri": re.compile(r"miri", re.I),
              "tsan": re.compile(r"thread sanitizer|tsan", re.I),
              "valgrind": re.compile(r"valgrind", re.I),
          }
          matched: dict[str, list[dict]] = {name: [] for name in categories}
          for item in evidence:
              searchable = "\n".join(
                  [item["workflow_name"], item["job_name"], *item["steps"]]
              )
              for name, pattern in categories.items():
                  if pattern.search(searchable):
                      matched[name].append(item)

          missing = [name for name, values in matched.items() if not values]
          payload = {
              "schema": 1,
              "repository": repository,
              "source_commit": sha,
              "required_categories": sorted(categories),
              "matched": matched,
              "all_successful_job_evidence": evidence,
              "missing": missing,
          }
          Path("security-evidence.json").write_text(
              json.dumps(payload, indent=2, sort_keys=True) + "\n",
              encoding="utf-8",
          )
          if missing:
              raise SystemExit(
                  "missing successful security evidence for: " + ", ".join(missing)
              )
          PY

      - name: Write bound proof
        shell: bash
        run: |
          set -euo pipefail
          mkdir -p proof
          cp security-evidence.json proof/security-evidence.json
          python3 scripts/write-replacement-proof.py \
            --gate security-suite \
            --result pass \
            --output proof/security-suite.json \
            --artifact proof/security-evidence.json \
            --metadata profiles=fuzz,asan,ubsan,miri,tsan,valgrind \
            --summary 'All required security profiles passed on this exact Git tree.'

      - name: Upload security proof
        uses: actions/upload-artifact@v4
        with:
          name: replacement-security-proof-${{ inputs.source_sha || github.sha }}
          path: proof
          if-no-files-found: error
          retention-days: 30

  report:
    name: Publish security proof status
    if: ${{ always() }}
    needs: [prove]
    runs-on: ubuntu-24.04
    steps:
      - name: Publish exact-source status
        env:
          GH_TOKEN: ${{ github.token }}
          SOURCE_SHA: ${{ inputs.source_sha || github.sha }}
          RESULT: ${{ needs.prove.result }}
        run: |
          set -euo pipefail
          state=failure
          if [[ "$RESULT" == success ]]; then
            state=success
          fi
          payload=$(printf '{"state":"%s","context":"replacement/security-proof","description":"Bound security proof %s","target_url":"%s"}' "$state" "$state" "${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}")
          curl --fail-with-body --silent --show-error -X POST \
            -H "Accept: application/vnd.github+json" \
            -H "Authorization: Bearer $GH_TOKEN" \
            -H "X-GitHub-Api-Version: 2022-11-28" \
            "${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/statuses/${SOURCE_SHA}" \
            --data "$payload" >/dev/null