Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions .github/workflows/cd-apply.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
timeout-minutes: 5
outputs:
contract_sha: ${{ steps.authorize.outputs.contract_sha }}
private_runner_allowed: ${{ steps.authorize.outputs.private_runner_allowed }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
Expand All @@ -31,13 +32,30 @@ jobs:
id: authorize
env:
CONTRACT_SHA: ${{ inputs.contract_sha }}
CALLER_PRIVATE: ${{ github.event.repository.private }}
CALLER_EVENT: ${{ github.event_name }}
CALLER_REF: ${{ github.ref }}
CALLER_DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
REQUIRES_PRIVATE_RUNNER: "true"
run: |
set -euo pipefail
private_runner_allowed=false
if [[ "$CALLER_PRIVATE" == true && -n "$CALLER_DEFAULT_BRANCH" &&
"$CALLER_REF" == "refs/heads/$CALLER_DEFAULT_BRANCH" &&
"$CALLER_EVENT" =~ ^(push|workflow_dispatch|schedule)$ ]]; then
private_runner_allowed=true
fi
if [[ "$REQUIRES_PRIVATE_RUNNER" == true && "$private_runner_allowed" != true ]]; then
echo 'Private CD runners require a trusted default-branch push, manual or scheduled caller.' >&2
exit 1
fi
[[ "$CONTRACT_SHA" =~ ^[0-9a-f]{40}$ ]]
git -C authority fetch --no-tags --depth=1 origin "$CONTRACT_SHA"
git -C authority cat-file -e "$CONTRACT_SHA^{commit}"
git -C authority merge-base --is-ancestor "$CONTRACT_SHA" refs/remotes/origin/main
printf 'contract_sha=%s\n' "$CONTRACT_SHA" >> "$GITHUB_OUTPUT"
printf 'contract_sha=%s\nprivate_runner_allowed=%s\n' "$CONTRACT_SHA" "$private_runner_allowed" >> "$GITHUB_OUTPUT"
apply:
if: ${{ needs.authorize-contract.outputs.private_runner_allowed == 'true' }}
needs: authorize-contract
runs-on: [self-hosted, cd-apply-out-of-band]
permissions:
Expand All @@ -59,6 +77,7 @@ jobs:
STATE_PATH: ${{ inputs.state_path }}
APPROVAL_PATH: ${{ inputs.approval_path }}
run: |
set -euo pipefail
[[ "$CONTRACT_SHA" =~ ^[0-9a-f]{40}$ ]]
[[ "$CONTRACT_SHA" == "$AUTHORIZED_CONTRACT_SHA" ]]
for value in "$PLAN_PATH" "$STATE_PATH" "$APPROVAL_PATH"; do
Expand All @@ -67,7 +86,7 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: NDDev-OpenNetwork/cd-workflows
ref: ${{ inputs.contract_sha }}
ref: ${{ needs.authorize-contract.outputs.contract_sha }}
persist-credentials: false
path: _cd
- name: Bind requested deployment
Expand Down
24 changes: 21 additions & 3 deletions .github/workflows/cd-evidence.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ jobs:
timeout-minutes: 5
outputs:
contract_sha: ${{ steps.authorize.outputs.contract_sha }}
private_runner_allowed: ${{ steps.authorize.outputs.private_runner_allowed }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
Expand All @@ -30,13 +31,28 @@ jobs:
id: authorize
env:
CONTRACT_SHA: ${{ inputs.contract_sha }}
CALLER_PRIVATE: ${{ github.event.repository.private }}
CALLER_EVENT: ${{ github.event_name }}
CALLER_REF: ${{ github.ref }}
CALLER_DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
REQUIRES_PRIVATE_RUNNER: "false"
run: |
set -euo pipefail
private_runner_allowed=false
if [[ "$CALLER_PRIVATE" == true && -n "$CALLER_DEFAULT_BRANCH" &&
"$CALLER_REF" == "refs/heads/$CALLER_DEFAULT_BRANCH" &&
"$CALLER_EVENT" =~ ^(push|workflow_dispatch|schedule)$ ]]; then
private_runner_allowed=true
fi
if [[ "$REQUIRES_PRIVATE_RUNNER" == true && "$private_runner_allowed" != true ]]; then
echo 'Private CD runners require a trusted default-branch push, manual or scheduled caller.' >&2
exit 1
fi
[[ "$CONTRACT_SHA" =~ ^[0-9a-f]{40}$ ]]
[[ "$CONTRACT_SHA" == "$AUTHORIZED_CONTRACT_SHA" ]]
git -C authority fetch --no-tags --depth=1 origin "$CONTRACT_SHA"
git -C authority cat-file -e "$CONTRACT_SHA^{commit}"
git -C authority merge-base --is-ancestor "$CONTRACT_SHA" refs/remotes/origin/main
printf 'contract_sha=%s\n' "$CONTRACT_SHA" >> "$GITHUB_OUTPUT"
printf 'contract_sha=%s\nprivate_runner_allowed=%s\n' "$CONTRACT_SHA" "$private_runner_allowed" >> "$GITHUB_OUTPUT"

validate:
needs: authorize-contract
Expand All @@ -50,12 +66,14 @@ jobs:
- name: Validate immutable inputs before contract checkout
env: {CONTRACT_SHA: "${{ inputs.contract_sha }}", AUTHORIZED_CONTRACT_SHA: "${{ needs.authorize-contract.outputs.contract_sha }}", PLAN_PATH: "${{ inputs.plan_path }}", STATE_PATH: "${{ inputs.state_path }}", EVIDENCE_PATH: "${{ inputs.evidence_path }}"}
run: |
set -euo pipefail
[[ "$CONTRACT_SHA" =~ ^[0-9a-f]{40}$ ]]
[[ "$CONTRACT_SHA" == "$AUTHORIZED_CONTRACT_SHA" ]]
for value in "$PLAN_PATH" "$STATE_PATH" "$EVIDENCE_PATH"; do
[[ "$value" =~ ^[A-Za-z0-9._/-]+$ && "$value" != /* && "$value" != *..* ]]
done
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with: {repository: NDDev-OpenNetwork/cd-workflows, ref: "${{ inputs.contract_sha }}", persist-credentials: false, path: _cd}
with: {repository: NDDev-OpenNetwork/cd-workflows, ref: "${{ needs.authorize-contract.outputs.contract_sha }}", persist-credentials: false, path: _cd}
- uses: ./_cd/.github/actions/contract
with:
command: validate-evidence
Expand Down
26 changes: 21 additions & 5 deletions .github/workflows/cd-plan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ jobs:
timeout-minutes: 5
outputs:
contract_sha: ${{ steps.authorize.outputs.contract_sha }}
private_runner_allowed: ${{ steps.authorize.outputs.private_runner_allowed }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
Expand All @@ -42,13 +43,28 @@ jobs:
id: authorize
env:
CONTRACT_SHA: ${{ inputs.contract_sha }}
CALLER_PRIVATE: ${{ github.event.repository.private }}
CALLER_EVENT: ${{ github.event_name }}
CALLER_REF: ${{ github.ref }}
CALLER_DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
REQUIRES_PRIVATE_RUNNER: ${{ inputs.execution_surface == 'out-of-band' }}
run: |
set -euo pipefail
private_runner_allowed=false
if [[ "$CALLER_PRIVATE" == true && -n "$CALLER_DEFAULT_BRANCH" &&
"$CALLER_REF" == "refs/heads/$CALLER_DEFAULT_BRANCH" &&
"$CALLER_EVENT" =~ ^(push|workflow_dispatch|schedule)$ ]]; then
private_runner_allowed=true
fi
if [[ "$REQUIRES_PRIVATE_RUNNER" == true && "$private_runner_allowed" != true ]]; then
echo 'Private CD runners require a trusted default-branch push, manual or scheduled caller.' >&2
exit 1
fi
[[ "$CONTRACT_SHA" =~ ^[0-9a-f]{40}$ ]]
[[ "$CONTRACT_SHA" == "$AUTHORIZED_CONTRACT_SHA" ]]
git -C authority fetch --no-tags --depth=1 origin "$CONTRACT_SHA"
git -C authority cat-file -e "$CONTRACT_SHA^{commit}"
git -C authority merge-base --is-ancestor "$CONTRACT_SHA" refs/remotes/origin/main
printf 'contract_sha=%s\n' "$CONTRACT_SHA" >> "$GITHUB_OUTPUT"
printf 'contract_sha=%s\nprivate_runner_allowed=%s\n' "$CONTRACT_SHA" "$private_runner_allowed" >> "$GITHUB_OUTPUT"

hosted:
if: ${{ inputs.execution_surface == 'hosted' }}
Expand Down Expand Up @@ -77,7 +93,7 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: NDDev-OpenNetwork/cd-workflows
ref: ${{ inputs.contract_sha }}
ref: ${{ needs.authorize-contract.outputs.contract_sha }}
persist-credentials: false
path: _cd
- name: Seal immutable plan
Expand All @@ -98,7 +114,7 @@ jobs:
retention-days: 30

out-of-band:
if: ${{ inputs.execution_surface == 'out-of-band' }}
if: ${{ inputs.execution_surface == 'out-of-band' && needs.authorize-contract.outputs.private_runner_allowed == 'true' }}
needs: authorize-contract
permissions:
contents: read
Expand All @@ -124,7 +140,7 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: NDDev-OpenNetwork/cd-workflows
ref: ${{ inputs.contract_sha }}
ref: ${{ needs.authorize-contract.outputs.contract_sha }}
persist-credentials: false
path: _cd
- name: Seal immutable plan
Expand Down
25 changes: 22 additions & 3 deletions .github/workflows/cd-resume.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
timeout-minutes: 5
outputs:
contract_sha: ${{ steps.authorize.outputs.contract_sha }}
private_runner_allowed: ${{ steps.authorize.outputs.private_runner_allowed }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
Expand All @@ -31,15 +32,31 @@ jobs:
id: authorize
env:
CONTRACT_SHA: ${{ inputs.contract_sha }}
CALLER_PRIVATE: ${{ github.event.repository.private }}
CALLER_EVENT: ${{ github.event_name }}
CALLER_REF: ${{ github.ref }}
CALLER_DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
REQUIRES_PRIVATE_RUNNER: "true"
run: |
set -euo pipefail
private_runner_allowed=false
if [[ "$CALLER_PRIVATE" == true && -n "$CALLER_DEFAULT_BRANCH" &&
"$CALLER_REF" == "refs/heads/$CALLER_DEFAULT_BRANCH" &&
"$CALLER_EVENT" =~ ^(push|workflow_dispatch|schedule)$ ]]; then
private_runner_allowed=true
fi
if [[ "$REQUIRES_PRIVATE_RUNNER" == true && "$private_runner_allowed" != true ]]; then
echo 'Private CD runners require a trusted default-branch push, manual or scheduled caller.' >&2
exit 1
fi
[[ "$CONTRACT_SHA" =~ ^[0-9a-f]{40}$ ]]
[[ "$CONTRACT_SHA" == "$AUTHORIZED_CONTRACT_SHA" ]]
git -C authority fetch --no-tags --depth=1 origin "$CONTRACT_SHA"
git -C authority cat-file -e "$CONTRACT_SHA^{commit}"
git -C authority merge-base --is-ancestor "$CONTRACT_SHA" refs/remotes/origin/main
printf 'contract_sha=%s\n' "$CONTRACT_SHA" >> "$GITHUB_OUTPUT"
printf 'contract_sha=%s\nprivate_runner_allowed=%s\n' "$CONTRACT_SHA" "$private_runner_allowed" >> "$GITHUB_OUTPUT"

resume:
if: ${{ needs.authorize-contract.outputs.private_runner_allowed == 'true' }}
needs: authorize-contract
permissions:
contents: read
Expand All @@ -56,12 +73,14 @@ jobs:
- name: Validate immutable inputs before contract checkout
env: {CONTRACT_SHA: "${{ inputs.contract_sha }}", AUTHORIZED_CONTRACT_SHA: "${{ needs.authorize-contract.outputs.contract_sha }}", PLAN_PATH: "${{ inputs.plan_path }}", STATE_PATH: "${{ inputs.state_path }}", APPROVAL_PATH: "${{ inputs.approval_path }}"}
run: |
set -euo pipefail
[[ "$CONTRACT_SHA" =~ ^[0-9a-f]{40}$ ]]
[[ "$CONTRACT_SHA" == "$AUTHORIZED_CONTRACT_SHA" ]]
for value in "$PLAN_PATH" "$STATE_PATH" "$APPROVAL_PATH"; do
[[ "$value" =~ ^[A-Za-z0-9._/-]+$ && "$value" != /* && "$value" != *..* ]]
done
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with: {repository: NDDev-OpenNetwork/cd-workflows, ref: "${{ inputs.contract_sha }}", persist-credentials: false, path: _cd}
with: {repository: NDDev-OpenNetwork/cd-workflows, ref: "${{ needs.authorize-contract.outputs.contract_sha }}", persist-credentials: false, path: _cd}
- name: Bind requested deployment
env: {DEPLOYMENT_ID: "${{ inputs.deployment_id }}", PLAN: "source/${{ inputs.plan_path }}"}
run: '[[ "$DEPLOYMENT_ID" =~ ^deploy_[0-9A-Z]{26}$ ]] && [[ "$(jq -er .deployment_id "$PLAN")" == "$DEPLOYMENT_ID" ]]'
Expand Down
25 changes: 22 additions & 3 deletions .github/workflows/cd-rollback.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
timeout-minutes: 5
outputs:
contract_sha: ${{ steps.authorize.outputs.contract_sha }}
private_runner_allowed: ${{ steps.authorize.outputs.private_runner_allowed }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
Expand All @@ -31,15 +32,31 @@ jobs:
id: authorize
env:
CONTRACT_SHA: ${{ inputs.contract_sha }}
CALLER_PRIVATE: ${{ github.event.repository.private }}
CALLER_EVENT: ${{ github.event_name }}
CALLER_REF: ${{ github.ref }}
CALLER_DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
REQUIRES_PRIVATE_RUNNER: "true"
run: |
set -euo pipefail
private_runner_allowed=false
if [[ "$CALLER_PRIVATE" == true && -n "$CALLER_DEFAULT_BRANCH" &&
"$CALLER_REF" == "refs/heads/$CALLER_DEFAULT_BRANCH" &&
"$CALLER_EVENT" =~ ^(push|workflow_dispatch|schedule)$ ]]; then
private_runner_allowed=true
fi
if [[ "$REQUIRES_PRIVATE_RUNNER" == true && "$private_runner_allowed" != true ]]; then
echo 'Private CD runners require a trusted default-branch push, manual or scheduled caller.' >&2
exit 1
fi
[[ "$CONTRACT_SHA" =~ ^[0-9a-f]{40}$ ]]
[[ "$CONTRACT_SHA" == "$AUTHORIZED_CONTRACT_SHA" ]]
git -C authority fetch --no-tags --depth=1 origin "$CONTRACT_SHA"
git -C authority cat-file -e "$CONTRACT_SHA^{commit}"
git -C authority merge-base --is-ancestor "$CONTRACT_SHA" refs/remotes/origin/main
printf 'contract_sha=%s\n' "$CONTRACT_SHA" >> "$GITHUB_OUTPUT"
printf 'contract_sha=%s\nprivate_runner_allowed=%s\n' "$CONTRACT_SHA" "$private_runner_allowed" >> "$GITHUB_OUTPUT"

rollback:
if: ${{ needs.authorize-contract.outputs.private_runner_allowed == 'true' }}
needs: authorize-contract
permissions:
contents: read
Expand All @@ -56,12 +73,14 @@ jobs:
- name: Validate immutable inputs before contract checkout
env: {CONTRACT_SHA: "${{ inputs.contract_sha }}", AUTHORIZED_CONTRACT_SHA: "${{ needs.authorize-contract.outputs.contract_sha }}", PLAN_PATH: "${{ inputs.plan_path }}", STATE_PATH: "${{ inputs.state_path }}", APPROVAL_PATH: "${{ inputs.approval_path }}"}
run: |
set -euo pipefail
[[ "$CONTRACT_SHA" =~ ^[0-9a-f]{40}$ ]]
[[ "$CONTRACT_SHA" == "$AUTHORIZED_CONTRACT_SHA" ]]
for value in "$PLAN_PATH" "$STATE_PATH" "$APPROVAL_PATH"; do
[[ "$value" =~ ^[A-Za-z0-9._/-]+$ && "$value" != /* && "$value" != *..* ]]
done
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with: {repository: NDDev-OpenNetwork/cd-workflows, ref: "${{ inputs.contract_sha }}", persist-credentials: false, path: _cd}
with: {repository: NDDev-OpenNetwork/cd-workflows, ref: "${{ needs.authorize-contract.outputs.contract_sha }}", persist-credentials: false, path: _cd}
- name: Bind requested deployment
env: {DEPLOYMENT_ID: "${{ inputs.deployment_id }}", PLAN: "source/${{ inputs.plan_path }}"}
run: '[[ "$DEPLOYMENT_ID" =~ ^deploy_[0-9A-Z]{26}$ ]] && [[ "$(jq -er .deployment_id "$PLAN")" == "$DEPLOYMENT_ID" ]]'
Expand Down
25 changes: 22 additions & 3 deletions .github/workflows/cd-verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ jobs:
timeout-minutes: 5
outputs:
contract_sha: ${{ steps.authorize.outputs.contract_sha }}
private_runner_allowed: ${{ steps.authorize.outputs.private_runner_allowed }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
Expand All @@ -30,15 +31,31 @@ jobs:
id: authorize
env:
CONTRACT_SHA: ${{ inputs.contract_sha }}
CALLER_PRIVATE: ${{ github.event.repository.private }}
CALLER_EVENT: ${{ github.event_name }}
CALLER_REF: ${{ github.ref }}
CALLER_DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
REQUIRES_PRIVATE_RUNNER: "true"
run: |
set -euo pipefail
private_runner_allowed=false
if [[ "$CALLER_PRIVATE" == true && -n "$CALLER_DEFAULT_BRANCH" &&
"$CALLER_REF" == "refs/heads/$CALLER_DEFAULT_BRANCH" &&
"$CALLER_EVENT" =~ ^(push|workflow_dispatch|schedule)$ ]]; then
private_runner_allowed=true
fi
if [[ "$REQUIRES_PRIVATE_RUNNER" == true && "$private_runner_allowed" != true ]]; then
echo 'Private CD runners require a trusted default-branch push, manual or scheduled caller.' >&2
exit 1
fi
[[ "$CONTRACT_SHA" =~ ^[0-9a-f]{40}$ ]]
[[ "$CONTRACT_SHA" == "$AUTHORIZED_CONTRACT_SHA" ]]
git -C authority fetch --no-tags --depth=1 origin "$CONTRACT_SHA"
git -C authority cat-file -e "$CONTRACT_SHA^{commit}"
git -C authority merge-base --is-ancestor "$CONTRACT_SHA" refs/remotes/origin/main
printf 'contract_sha=%s\n' "$CONTRACT_SHA" >> "$GITHUB_OUTPUT"
printf 'contract_sha=%s\nprivate_runner_allowed=%s\n' "$CONTRACT_SHA" "$private_runner_allowed" >> "$GITHUB_OUTPUT"

verify:
if: ${{ needs.authorize-contract.outputs.private_runner_allowed == 'true' }}
needs: authorize-contract
permissions:
contents: read
Expand All @@ -53,12 +70,14 @@ jobs:
- name: Validate immutable inputs before contract checkout
env: {CONTRACT_SHA: "${{ inputs.contract_sha }}", AUTHORIZED_CONTRACT_SHA: "${{ needs.authorize-contract.outputs.contract_sha }}", PLAN_PATH: "${{ inputs.plan_path }}", STATE_PATH: "${{ inputs.state_path }}"}
run: |
set -euo pipefail
[[ "$CONTRACT_SHA" =~ ^[0-9a-f]{40}$ ]]
[[ "$CONTRACT_SHA" == "$AUTHORIZED_CONTRACT_SHA" ]]
for value in "$PLAN_PATH" "$STATE_PATH"; do
[[ "$value" =~ ^[A-Za-z0-9._/-]+$ && "$value" != /* && "$value" != *..* ]]
done
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with: {repository: NDDev-OpenNetwork/cd-workflows, ref: "${{ inputs.contract_sha }}", persist-credentials: false, path: _cd}
with: {repository: NDDev-OpenNetwork/cd-workflows, ref: "${{ needs.authorize-contract.outputs.contract_sha }}", persist-credentials: false, path: _cd}
- name: Bind requested deployment
env: {DEPLOYMENT_ID: "${{ inputs.deployment_id }}", PLAN: "source/${{ inputs.plan_path }}"}
run: '[[ "$DEPLOYMENT_ID" =~ ^deploy_[0-9A-Z]{26}$ ]] && [[ "$(jq -er .deployment_id "$PLAN")" == "$DEPLOYMENT_ID" ]]'
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ Versioning.

## [Unreleased]

- Repair five contract-authorization workflows that compared an input with an
unset authorization output before producing it. Execute regression tests
against the actual shell blocks and use the verified output for every contract
checkout. Restrict private CD runners to trusted default-branch callers.

- Select continuous-development so ordinary merge does not wait on the
`test` GitHub required check; local `verification.required` stays.

Expand Down
Loading