# ACDL Reusable Deploy Workflow — Gitea Actions (dev environment) # # This reusable workflow implements the central deployment pipeline contract: # pipelines/deploy.yaml (validated against schemas/deploy-pipeline.schema.json) # # The same contract is implemented by .github/workflows/deploy.yml (GitHub # Actions, production). Both files must be byte-identical — the only # declared difference is the forge/runtime, not the stages or commands. # # Consumer repos invoke this workflow via a versioned tag (floating MAJOR + MINOR): # uses: acdl/.gitea/workflows/deploy.yml@v1.6 (Gitea) # uses: acdl/.github/workflows/deploy.yml@v1.6 (GitHub) # # Unversioned references (@main, bare) are discouraged — the consumer's setup # must be immutable + resilient. The versioned tag is the only immutability # lever (version constraints cannot be expressed inside the contract). # # What this workflow does: # 1. Checks out the consumer repo (the repo that invoked the workflow). # 2. Checks out the ACDL platform repo into the workspace (platform/). # This is the run-time fetch — consumers never clone the platform repo. # 3. Installs runtime deps: Python 3.12, Terraform 1.9.*, Checkov. # 4. Configures AWS auth (OIDC default; static-key override via secrets). # 5. Runs scripts/run_platform.sh against the consumer's contract path. # 6. Uploads artifacts (emitted Terraform, Checkov JSON, confidence JSON, # platform log) for auditability. # # Inputs: # contract — path to the consumer's contract YAML (default .acdl/contract.yaml) # mode — full | plan-only | check-only (default full; dev = full apply, # higher environments hold for HITL — the calling repo or the # forge environment gate enforces that) # # Auth (zero-trust default — see README.md#credentials--zero-trust): # OIDC federation is the default. permissions: id-token: write lets the # forge mint a short-lived STS token. The role-to-assume is scoped by the # consumer's repository identity (ABAC) — the workflow assumes the role # that matches repo:org/consumer-repo:ref:refs/heads/main, and the session # policy restricts view/update to resources tagged acdl:owner=. # # Override (where OIDC is unavailable, e.g. Gitea pending # go-gitea/gitea#36988): set ACDL_AWS_ACCESS_KEY_ID + ACDL_AWS_SECRET_ACCESS_KEY # as repository secrets. The platform-managed scheduled pipeline rotates # the key on a daily cadence. When .env.secrets is used locally instead, # rotating the key out of band is the consumer's responsibility. name: acdl-deploy on: workflow_call: inputs: contract: description: Path to the consumer contract YAML (in the consumer repo) type: string default: .acdl/contract.yaml mode: description: Pipeline mode — full (apply), plan-only, check-only, or decommission type: string default: full changeRequestId: description: Change request ID (required for decommission mode — validated against CMDB) type: string default: "" environment: description: Target environment override (dev/qa/prod/dr); when empty, the contract's environment field is used type: string default: "" permissions: id-token: write contents: read jobs: deploy: name: Deploy runs-on: ubuntu-latest steps: - name: Check out consumer repo uses: actions/checkout@v4 - name: Check out ACDL platform repo uses: actions/checkout@v4 with: repository: acdl/acdl path: platform ref: v1.6 - uses: actions/setup-python@v5 with: python-version: "3.12" - name: Install runtime dependencies run: | pip install --break-system-packages jsonschema pyyaml boto3 pip install --break-system-packages "checkov>=3.2,<4" - name: Install Terraform 1.9.* run: | wget -qO- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp.gpg echo "deb [signed-by=/usr/share/keyrings/hashicorp.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list sudo apt-get update && sudo apt-get install -y terraform=1.9.* - name: Configure AWS credentials (OIDC default + static-key override) uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: ${{ secrets.ACDL_AWS_ACCESS_KEY_ID == '' && format('arn:aws:iam::{0}:role/acdl-deploy-{1}', secrets.ACDL_AWS_ACCOUNT_ID, github.repository_id) || '' }} aws-region: us-east-1 access-key-id: ${{ secrets.ACDL_AWS_ACCESS_KEY_ID }} secret-access-key: ${{ secrets.ACDL_AWS_SECRET_ACCESS_KEY }} - name: Run the platform pipeline working-directory: ${{ github.workspace }} run: | MODE_FLAG="" case "${{ inputs.mode }}" in full) MODE_FLAG="" ;; plan-only) MODE_FLAG="--plan-only" ;; check-only) MODE_FLAG="--check-only" ;; decommission) if [ -z "${{ inputs.changeRequestId }}" ]; then echo "FAIL: changeRequestId is required for decommission mode" exit 1 fi MODE_FLAG="--decommission ${{ inputs.changeRequestId }}" ;; *) echo "Unknown mode: ${{ inputs.mode }}"; exit 1 ;; esac ENV_FLAG="" if [ -n "${{ inputs.environment }}" ]; then ENV_FLAG="--environment ${{ inputs.environment }}" fi bash platform/scripts/run_platform.sh $MODE_FLAG $ENV_FLAG "${{ inputs.contract }}" - name: Post stage summary comment to PR if: success() && github.event_name == 'pull_request' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_REPOSITORY: ${{ github.repository }} GITHUB_REF: ${{ github.ref }} run: | bash platform/scripts/post_stage_comment.sh deploy pass '{"mode":"${{ inputs.mode }}","runId":"${{ github.run_id }}"}' - name: Report error to platform team (on failure) if: failure() env: AWS_DEFAULT_REGION: us-east-1 run: | aws lambda invoke-function-url \ --function-url "${{ secrets.ACDL_LAMBDA_URL }}" \ --cli-binary-format raw-in-base64-out \ --payload "$(python3 -c "import json,os; print(json.dumps({'action':'report_error','consumerRepo':os.environ.get('GITHUB_REPOSITORY',''),'contractId':'${{ github.run_id }}','error':'Deploy pipeline failed. See run logs.','runUrl':'${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}','environment':'dev'}))")" \ /dev/null || true - name: Upload emitted Terraform uses: actions/upload-artifact@v4 with: name: acdl-terraform path: /tmp/acdl_platform_run_v18/tf/*.tf if-no-files-found: warn - name: Upload platform log uses: actions/upload-artifact@v4 with: name: acdl-platform-log path: platform/logs/ if-no-files-found: warn