Skip to content
Draft
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
3 changes: 3 additions & 0 deletions .github/actionlint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
self-hosted-runner:
labels:
- tinyland-nix
53 changes: 8 additions & 45 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
@@ -1,51 +1,14 @@
name: CD
name: ACL CD (retired tombstone)

on:
push:
branches: [main]
workflow_dispatch:

concurrency:
group: acl-deploy
cancel-in-progress: false

permissions:
contents: read
permissions: {}

jobs:
deploy:
name: Build, validate, push ACL
runs-on: ubuntu-latest
environment: production
retired:
if: ${{ github.repository == 'invalid/retired-tailnet-acl-cd' }}
runs-on: tinyland-nix
steps:
- uses: actions/checkout@v4

- uses: DeterminateSystems/nix-installer-action@main
- uses: DeterminateSystems/magic-nix-cache-action@main

- name: Build policy JSON
run: nix develop --command just build
env:
XDG_CACHE_HOME: ${{ runner.temp }}/.cache

- name: Validate against live ACL
continue-on-error: true
run: nix develop --command python3 scripts/validate.py
env:
TAILSCALE_API_KEY: ${{ secrets.TAILSCALE_API_KEY }}
TS_OAUTH_CLIENT_ID: ${{ vars.TS_OAUTH_CLIENT_ID }}
XDG_CACHE_HOME: ${{ runner.temp }}/.cache

- name: Show diff
run: |
nix develop --command python3 scripts/push.py --dry-run || true
env:
TAILSCALE_API_KEY: ${{ secrets.TAILSCALE_API_KEY }}
TS_OAUTH_CLIENT_ID: ${{ vars.TS_OAUTH_CLIENT_ID }}
XDG_CACHE_HOME: ${{ runner.temp }}/.cache

- name: Push ACL to Tailscale
run: nix develop --command python3 scripts/push.py --confirm
env:
TAILSCALE_API_KEY: ${{ secrets.TAILSCALE_API_KEY }}
TS_OAUTH_CLIENT_ID: ${{ vars.TS_OAUTH_CLIENT_ID }}
XDG_CACHE_HOME: ${{ runner.temp }}/.cache
- name: Refuse retired ACL publication workflow
run: exit 1
147 changes: 26 additions & 121 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,41 @@ on:

permissions:
contents: read
pull-requests: write

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
secrets:
name: Secret detection
runs-on: ubuntu-latest
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
runs-on: tinyland-nix
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
fetch-depth: 0
persist-credentials: false
ref: ${{ github.event.pull_request.head.sha || github.sha }}

- uses: gitleaks/gitleaks-action@v2
- uses: gitleaks/gitleaks-action@ff98106e4c7b2bc287b24eaf42907196329070c7 # v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ github.token }}

check:
name: Dhall type-check + build
runs-on: ubuntu-latest
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
runs-on: tinyland-nix
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
persist-credentials: false
ref: ${{ github.event.pull_request.head.sha || github.sha }}

- uses: DeterminateSystems/nix-installer-action@main
- uses: DeterminateSystems/magic-nix-cache-action@main
- name: Validate workflow syntax
run: nix develop --command actionlint -color=false
env:
XDG_CACHE_HOME: ${{ runner.temp }}/.cache

- name: Dhall type-check
run: nix develop --command dhall type --file policy.dhall > /dev/null
Expand Down Expand Up @@ -77,121 +89,14 @@ jobs:
print(f' {len(p[\"tagOwners\"])} tag owners')
"

- name: Policy contract tests
run: python3 -m unittest discover -s tests -p 'test_*.py'
- name: Policy and workflow authority contract tests
run: nix develop --command python3 -m unittest discover -s tests -p 'test_*.py'
env:
PYTHONDONTWRITEBYTECODE: "1"

- name: Upload policy artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: policy-json
path: generated/policy.json
retention-days: 30

validate:
name: Validate against live ACL
runs-on: ubuntu-latest
needs: [check, secrets]
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v4

- uses: DeterminateSystems/nix-installer-action@main
- uses: DeterminateSystems/magic-nix-cache-action@main

- name: Build policy
run: nix develop --command just build
env:
XDG_CACHE_HOME: ${{ runner.temp }}/.cache

- name: Validate against live
id: validate
run: |
set +e
OUTPUT=$(nix develop --command python3 scripts/validate.py 2>&1)
EXIT_CODE=$?
echo "$OUTPUT"
# Save for PR comment
{
echo 'validation_output<<EOF'
echo "$OUTPUT"
echo 'EOF'
} >> "$GITHUB_OUTPUT"
echo "exit_code=$EXIT_CODE" >> "$GITHUB_OUTPUT"
if [ "$EXIT_CODE" -eq 0 ]; then
exit 0
fi

if printf '%s\n' "$OUTPUT" | grep -q 'Validation FAILED: local policy differs from live.'; then
echo "::warning::Local policy differs from live; this PR check is advisory. The CD workflow applies the policy after merge to main."
exit 0
fi

exit "$EXIT_CODE"
env:
TAILSCALE_API_KEY: ${{ secrets.TAILSCALE_API_KEY }}
XDG_CACHE_HOME: ${{ runner.temp }}/.cache

- name: Diff summary
if: always()
id: diff
run: |
set +e
OUTPUT=$(nix develop --command python3 scripts/push.py --dry-run 2>&1)
{
echo 'diff_output<<EOF'
echo "$OUTPUT"
echo 'EOF'
} >> "$GITHUB_OUTPUT"
env:
TAILSCALE_API_KEY: ${{ secrets.TAILSCALE_API_KEY }}
XDG_CACHE_HOME: ${{ runner.temp }}/.cache

- name: Comment on PR
if: always()
uses: actions/github-script@v7
with:
script: |
const validate = `${{ steps.validate.outputs.validation_output }}`;
const diff = `${{ steps.diff.outputs.diff_output }}`;
const exitCode = '${{ steps.validate.outputs.exit_code }}';
const icon = exitCode === '0' ? ':white_check_mark:' : ':warning:';

const body = [
`## ${icon} ACL Validation`,
'',
'### Validation',
'```',
validate,
'```',
'',
diff ? '### Diff against live' : '',
diff ? '```' : '',
diff || '',
diff ? '```' : '',
].filter(Boolean).join('\n');

// Find existing comment
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const existing = comments.find(c =>
c.user.type === 'Bot' && c.body.includes('ACL Validation')
);

if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
}
Loading
Loading