fix(admin): restrict admin-only routes to administrators #4737
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Query Counts — Label | |
| # Manages the "query-count changed" label and a diff comment on PRs that | |
| # alter per-route DB query counts. When a PR's snapshot files differ from | |
| # base, the label and a comparison comment are added; when they match base | |
| # again (e.g. the delta was reverted, or base caught up via a merge), both | |
| # are removed. | |
| # | |
| # Deliberately NOT path-filtered. A `paths:` filter would create a catch-22: | |
| # the workflow could never run to clear a stale label/comment once a | |
| # previously-changed snapshot matched base again, because at that point the | |
| # PR diff no longer touches the snapshot files. The script below is cheap | |
| # (a couple of API reads) and decides what to do from the actual base/head | |
| # diff on every run. | |
| on: | |
| pull_request_target: | |
| branches: [main] | |
| types: [opened, synchronize, reopened, edited] | |
| permissions: | |
| pull-requests: write | |
| jobs: | |
| label: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 5 | |
| steps: | |
| - name: Sync query-count label and diff comment | |
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | |
| with: | |
| script: | | |
| const { owner, repo } = context.repo; | |
| const pr = context.payload.pull_request; | |
| const baseRef = pr.base.sha; | |
| const headRef = pr.head.sha; | |
| const label = 'query-count changed'; | |
| // Fetch a JSON file at a given ref. Returns {} if the file | |
| // doesn't exist on that ref (e.g. snapshot added in this PR). | |
| async function loadSnapshot(ref, path) { | |
| try { | |
| const { data } = await github.rest.repos.getContent({ | |
| owner, | |
| repo, | |
| ref, | |
| path, | |
| }); | |
| if (Array.isArray(data) || data.type !== 'file' || !data.content) { | |
| return {}; | |
| } | |
| const raw = Buffer.from(data.content, 'base64').toString('utf8'); | |
| return JSON.parse(raw); | |
| } catch (err) { | |
| if (err.status === 404) return {}; | |
| throw err; | |
| } | |
| } | |
| function diffRows(before, after) { | |
| const keys = new Set([...Object.keys(before), ...Object.keys(after)]); | |
| const rows = []; | |
| for (const key of [...keys].sort()) { | |
| const b = before[key]; | |
| const a = after[key]; | |
| if (b === a) continue; | |
| const bCell = b === undefined ? '—' : String(b); | |
| const aCell = a === undefined ? '—' : String(a); | |
| const delta = (a ?? 0) - (b ?? 0); | |
| const deltaCell = | |
| a === undefined | |
| ? 'removed' | |
| : b === undefined | |
| ? 'added' | |
| : delta > 0 | |
| ? `+${delta}` | |
| : String(delta); | |
| rows.push(`| \`${key}\` | ${bCell} | ${aCell} | ${deltaCell} |`); | |
| } | |
| return rows; | |
| } | |
| const dialects = [ | |
| ['SQLite', 'scripts/query-counts.snapshot.sqlite.json'], | |
| ['D1', 'scripts/query-counts.snapshot.d1.json'], | |
| ]; | |
| const sections = []; | |
| let totalDelta = 0; | |
| let totalChanged = 0; | |
| for (const [name, path] of dialects) { | |
| const [before, after] = await Promise.all([ | |
| loadSnapshot(baseRef, path), | |
| loadSnapshot(headRef, path), | |
| ]); | |
| const rows = diffRows(before, after); | |
| if (rows.length === 0) continue; | |
| totalChanged += rows.length; | |
| for (const key of new Set([...Object.keys(before), ...Object.keys(after)])) { | |
| const b = before[key] ?? 0; | |
| const a = after[key] ?? 0; | |
| if (a !== b) totalDelta += a - b; | |
| } | |
| sections.push( | |
| [ | |
| `### ${name}`, | |
| '', | |
| '| Route | Before | After | Δ |', | |
| '| --- | ---: | ---: | --- |', | |
| ...rows, | |
| ].join('\n'), | |
| ); | |
| } | |
| const hasChange = sections.length > 0; | |
| // Label: present iff the snapshots differ from base on this run. | |
| if (hasChange) { | |
| try { | |
| await github.rest.issues.createLabel({ | |
| owner, | |
| repo, | |
| name: label, | |
| color: 'fbca04', | |
| description: 'PR diff modifies query-count snapshot files', | |
| }); | |
| } catch (err) { | |
| if (err.status !== 422) throw err; // 422 = already exists | |
| } | |
| await github.rest.issues.addLabels({ | |
| owner, | |
| repo, | |
| issue_number: pr.number, | |
| labels: [label], | |
| }); | |
| } else { | |
| try { | |
| await github.rest.issues.removeLabel({ | |
| owner, | |
| repo, | |
| issue_number: pr.number, | |
| name: label, | |
| }); | |
| } catch (err) { | |
| if (err.status !== 404) throw err; // 404 = label not applied | |
| } | |
| } | |
| // Comment: upsert when changed, delete when not. | |
| const marker = '<!-- query-count-diff -->'; | |
| const comments = await github.paginate(github.rest.issues.listComments, { | |
| owner, | |
| repo, | |
| issue_number: pr.number, | |
| per_page: 100, | |
| }); | |
| const prior = comments.find( | |
| (c) => typeof c.body === 'string' && c.body.includes(marker), | |
| ); | |
| if (!hasChange) { | |
| // Snapshots match base on this run; remove any stale comment | |
| // (e.g. an earlier push had a delta that base has since caught | |
| // up to, or it was reverted). | |
| if (prior) { | |
| await github.rest.issues.deleteComment({ | |
| owner, | |
| repo, | |
| comment_id: prior.id, | |
| }); | |
| } | |
| return; | |
| } | |
| const sign = totalDelta > 0 ? '+' : ''; | |
| const summary = `**${totalChanged}** route${totalChanged === 1 ? '' : 's'} changed, total Δ ${sign}${totalDelta} quer${Math.abs(totalDelta) === 1 ? 'y' : 'ies'}.`; | |
| const body = [ | |
| marker, | |
| '## Query-count snapshot changes', | |
| '', | |
| summary, | |
| '', | |
| ...sections, | |
| '', | |
| '<sub>Comparing snapshot files between base and head. Updated automatically on each push.</sub>', | |
| ].join('\n'); | |
| if (prior) { | |
| await github.rest.issues.updateComment({ | |
| owner, | |
| repo, | |
| comment_id: prior.id, | |
| body, | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner, | |
| repo, | |
| issue_number: pr.number, | |
| body, | |
| }); | |
| } |