summaryrefslogtreecommitdiff
path: root/.github/workflows/deploy.yml
blob: fd1587e060f01a6b18a871b0c1a41a8bd8f238fd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
name: Deploy legacy snapshot worker
on:
  workflow_dispatch:
    inputs:
      promote:
        description: "false = candidate only; true = promote to production worker"
        type: boolean
        default: false
      force_pdf_refresh:
        description: "true = re-fetch + re-upload the 1.3 PDF even if it already exists in R2"
        type: boolean
        default: false
permissions:
  contents: read
# Never cancel a mid-flight deploy — queue behind it instead (fleet parity).
concurrency:
  group: legacy-deploy
  cancel-in-progress: false
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with: { persist-credentials: false }
      - uses: actions/checkout@v4
        with: { repository: vyos/vyos-documentation, ref: rolling, path: docsrepo, persist-credentials: false }
      - uses: actions/setup-node@v4
        with: { node-version: 22 }
      # Runs BEFORE the Worker deploy (fail fast): if the PDF can't be fetched, validated,
      # and secured in R2, no Worker goes live — otherwise a promote=true run could leave
      # production serving HTML whose legacy-PDF link 404s, violating the spec §5 site+PDF
      # consistency invariant the main pipeline enforces.
      - name: Upload legacy 1.3 PDF to R2 (apex §5 fallback source)
        env:
          CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN_DOCS }}
          CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
        run: |
          set -eu
          cd docsrepo/workers && npm ci   # the Deploy step's own npm ci re-run is a fast no-op

          R2_KEY="vyos-docs-artifacts/legacy/1.3/vyos-documentation.pdf"
          # 1.2/1.3 are frozen (spec §15a) — once the PDF is seeded in R2 it never
          # changes, and after RTD sunsets, docs.vyos.io/_/downloads/... is gone, so
          # re-dispatching this workflow must not depend on re-fetching it. Probe
          # existence first (wrangler r2 has no head-only verb; `get --pipe` is the
          # cheapest existence check the CLI exposes) and skip fetch+upload on a hit.
          if [ '${{ inputs.force_pdf_refresh }}' != 'true' ] && \
             npx wrangler r2 object get "$R2_KEY" --remote --pipe >/dev/null 2>/tmp/r2-probe.log; then
            echo "PDF already present at $R2_KEY — skipping fetch+upload (force_pdf_refresh=false)"
            exit 0
          fi

          # r2-staging/ (tools/snapshot.sh's local output) is gitignored, so CI re-fetches
          # from the pre-sunset RTD source directly. Browser-UA + retry added defensively:
          # tools/snapshot.sh's wget mirror crawl needed a browser UA to pass Cloudflare's
          # managed challenge, while its own PDF curl needed neither locally — but CI's
          # IP/request pattern differs, so both guards are cheap insurance here.
          # 29.2 MiB > the 25 MiB Worker per-asset cap, so this artifact never lands in
          # the deploy's dist/assets/ below — it goes straight to the shared
          # vyos-docs-artifacts R2 bucket the apex Worker's DOCS_PDFS binding reads
          # (workers/apex/wrangler.jsonc in vyos-documentation, both envs).
          curl -fL --retry 5 --retry-delay 5 \
               --user-agent "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0 Safari/537.36" \
               "https://docs.vyos.io/_/downloads/en/1.3/pdf/" -o /tmp/vyos-documentation-1.3.pdf

          size=$(stat -c%s /tmp/vyos-documentation-1.3.pdf)
          min=$((25*1024*1024)); max=$((35*1024*1024))
          if [ "$size" -le "$min" ] || [ "$size" -ge "$max" ]; then
            echo "PDF size sanity check FAILED: got $size bytes, expected strictly between $min and $max bytes (25-35 MiB)"
            exit 1
          fi
          echo "PDF size OK: $size bytes"

          header=$(head -c 5 /tmp/vyos-documentation-1.3.pdf)
          if [ "$header" != "%PDF-" ]; then
            echo "PDF content validation FAILED: file does not start with %PDF- (got: $header)"
            exit 1
          fi
          echo "PDF content OK: %PDF- header present"

          npx wrangler r2 object put "$R2_KEY" \
            --file /tmp/vyos-documentation-1.3.pdf --remote
      - name: Deploy
        env:
          CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN_DOCS }}
          CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
        run: |
          set -eu
          mkdir -p docsrepo/dist/assets && cp -r snapshot/. docsrepo/dist/assets/
          cd docsrepo/workers && npm ci
          name="vyos-docs-legacy$( [ '${{ inputs.promote }}' = 'true' ] || echo '-candidate' )"
          envv="$( [ '${{ inputs.promote }}' = 'true' ] && echo production || echo canary )"
          npx wrangler deploy --config branch/wrangler.legacy.jsonc \
            --name "$name" --var DOCS_BUILD_SHA:'${{ github.sha }}' --var DOCS_ENV:"$envv"