@biffo/cli 0.244.8 → 0.244.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/_skeletons/plugin-template/.github/workflows/codeql.yml +65 -0
- package/_skeletons/sibling-template/README.md +15 -14
- package/package.json +1 -1
- package/_skeletons/sibling-template/apps/frontend/src/app/example/members/page.tsx +0 -31
- package/_skeletons/sibling-template/apps/frontend/src/app/example/page.tsx +0 -24
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
name: 'CodeQL'
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [dev, staging, main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [dev, staging, main]
|
|
8
|
+
schedule:
|
|
9
|
+
# Weekly catch-up scan (Tuesday 05:17 UTC) for issues that land outside
|
|
10
|
+
# PR review (e.g. direct merges onto a branch).
|
|
11
|
+
- cron: '17 5 * * 2'
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
analyze:
|
|
15
|
+
name: Analyze (${{ matrix.language }})
|
|
16
|
+
runs-on: ${{ vars.RUNNER_LABEL || 'ubuntu-latest' }}
|
|
17
|
+
# CodeQL code scanning requires GitHub Advanced Security (GHAS) on private
|
|
18
|
+
# repos — the analysis runs but the SARIF upload fails without it. So this
|
|
19
|
+
# is opt-in: enable GHAS on the repo, then set the repo variable
|
|
20
|
+
# ENABLE_CODE_SCANNING=true. Left dormant (not failing) otherwise.
|
|
21
|
+
# See biffo-template's codeql.yml for the full reasoning (#1214): a public
|
|
22
|
+
# repo can scan for free, so it does; a private one still needs the opt-in.
|
|
23
|
+
# Both existing plugin repos are public, so this scans them for nothing —
|
|
24
|
+
# which is exactly why their never having been scanned was worth fixing
|
|
25
|
+
# (#1224).
|
|
26
|
+
if: github.event.repository.private == false || vars.ENABLE_CODE_SCANNING == 'true'
|
|
27
|
+
timeout-minutes: 15
|
|
28
|
+
permissions:
|
|
29
|
+
# Required for CodeQL to upload SARIF results.
|
|
30
|
+
security-events: write
|
|
31
|
+
contents: read
|
|
32
|
+
actions: read
|
|
33
|
+
|
|
34
|
+
strategy:
|
|
35
|
+
fail-fast: false
|
|
36
|
+
matrix:
|
|
37
|
+
include:
|
|
38
|
+
- language: javascript-typescript
|
|
39
|
+
build-mode: none
|
|
40
|
+
- language: python
|
|
41
|
+
build-mode: none
|
|
42
|
+
|
|
43
|
+
steps:
|
|
44
|
+
- name: Checkout repository
|
|
45
|
+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
|
|
46
|
+
|
|
47
|
+
- name: Initialize CodeQL
|
|
48
|
+
uses: github/codeql-action/init@v4
|
|
49
|
+
with:
|
|
50
|
+
languages: ${{ matrix.language }}
|
|
51
|
+
build-mode: ${{ matrix.build-mode }}
|
|
52
|
+
queries: security-extended
|
|
53
|
+
|
|
54
|
+
# autobuild intentionally omitted (build-mode 'none'):
|
|
55
|
+
# - the plugin's Python (src/, tests/) has no build step CodeQL needs.
|
|
56
|
+
# - javascript-typescript is declared even though a fresh plugin ships no
|
|
57
|
+
# web/ directory: the skeleton itself carries scripts/*.mjs, and every
|
|
58
|
+
# real plugin grows web/ and web-admin/ (both existing ones have them).
|
|
59
|
+
# Declaring it only once a plugin gains a frontend would mean the scan
|
|
60
|
+
# silently covers less than it appears to — the shape #1270 records for
|
|
61
|
+
# the dependency audits.
|
|
62
|
+
- name: Perform CodeQL Analysis
|
|
63
|
+
uses: github/codeql-action/analyze@v4
|
|
64
|
+
with:
|
|
65
|
+
category: '/language:${{ matrix.language }}'
|
|
@@ -34,9 +34,10 @@ anywhere in `services/api/`, on purpose.
|
|
|
34
34
|
|
|
35
35
|
```
|
|
36
36
|
apps/frontend/ # Next.js 15 static export. `/` is the SSO demo ("<name> - Hello <username>",
|
|
37
|
-
# proving the shared-session SSO works
|
|
38
|
-
# src/
|
|
39
|
-
# ("Your app goes here" below). src/lib/auth.ts reads
|
|
37
|
+
# proving the shared-session SSO works end to end, gate included);
|
|
38
|
+
# src/lib/auth-gate.tsx is the reusable wrapper for any OTHER page that
|
|
39
|
+
# needs the same gate ("Your app goes here" below). src/lib/auth.ts reads
|
|
40
|
+
# the shared session.
|
|
40
41
|
services/api/ # FastAPI + Mangum backend. Verifies the core project's Cognito JWT itself
|
|
41
42
|
# (defense in depth — API Gateway's own JWT authorizer is the first layer).
|
|
42
43
|
# core_client.py is the ONLY sanctioned way to reach core-owned data.
|
|
@@ -81,12 +82,10 @@ else depends on it.
|
|
|
81
82
|
This is a Next.js **App Router** app with `output: 'export'` (a static site).
|
|
82
83
|
A route is just a folder with a `page.tsx` under `apps/frontend/src/app/`:
|
|
83
84
|
|
|
84
|
-
| File
|
|
85
|
-
|
|
|
86
|
-
| `src/app/page.tsx`
|
|
87
|
-
| `src/app/pricing/page.tsx`
|
|
88
|
-
| `src/app/example/page.tsx` | `/example/` (public example, below) |
|
|
89
|
-
| `src/app/example/members/page.tsx` | `/example/members/` (gated example) |
|
|
85
|
+
| File | URL served |
|
|
86
|
+
| --------------------------- | --------------------------------- |
|
|
87
|
+
| `src/app/page.tsx` | `/` (the demo — replace or keep) |
|
|
88
|
+
| `src/app/pricing/page.tsx` | `/pricing/` |
|
|
90
89
|
|
|
91
90
|
**The `basePath` / `PATH_PREFIX` wiring is automatic — don't hand-write it.**
|
|
92
91
|
The core project's CloudFront routes `baseurl.com/<name>/*` to this sibling and
|
|
@@ -116,8 +115,7 @@ browser never holds a core credential.
|
|
|
116
115
|
|
|
117
116
|
The go-live state for most products is a **public** app. That is the easy path
|
|
118
117
|
here: any `page.tsx` you add is served **unauthenticated** the moment it
|
|
119
|
-
deploys — no auth code, no bounce
|
|
120
|
-
demonstration of exactly that; copy it or delete it.
|
|
118
|
+
deploys — no auth code, no bounce, nothing to opt out of.
|
|
121
119
|
|
|
122
120
|
When a page _does_ need a signed-in user, opt in with the `<AuthGate>` helper
|
|
123
121
|
(`src/lib/auth-gate.tsx`) — one wrapper, and only that page becomes private:
|
|
@@ -142,15 +140,18 @@ export default function Dashboard() {
|
|
|
142
140
|
A signed-out visitor is redirected to the core portal's login and returned to
|
|
143
141
|
that exact route afterwards; a signed-in visitor sees the content. `AuthGate`
|
|
144
142
|
builds on `getCurrentSession`/`auth.ts` and never signs anyone in itself
|
|
145
|
-
(ADR-0007)
|
|
146
|
-
|
|
143
|
+
(ADR-0007) — it is the same round-trip `/` already runs, packaged as a
|
|
144
|
+
one-line wrapper for any page besides `/`. Wrap only what must be private —
|
|
145
|
+
never gate the whole app. There is no separate demo route for this: `/`
|
|
146
|
+
already proves the mechanism works end to end, and the snippet above is the
|
|
147
|
+
runnable form.
|
|
147
148
|
|
|
148
149
|
### The path a founder actually walks
|
|
149
150
|
|
|
150
151
|
1. Run locally (`pnpm dev`, below) and open `/` — watch the SSO demo work.
|
|
151
152
|
2. Replace `src/app/page.tsx` with your own public home page (or add
|
|
152
153
|
`src/app/<something>/page.tsx`). It's public by default — that's your
|
|
153
|
-
go-live state.
|
|
154
|
+
go-live state.
|
|
154
155
|
3. For any area that needs a login, wrap its `page.tsx` in `<AuthGate>`.
|
|
155
156
|
4. Push to `main`; `deploy.yml` builds the static export with the right
|
|
156
157
|
`NEXT_PUBLIC_BASE_PATH` and syncs it to S3 behind the core CloudFront —
|
package/package.json
CHANGED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { AuthGate } from '@/lib/auth-gate'
|
|
4
|
-
|
|
5
|
-
// The SAME page, made private by a single wrapper. Opting into auth is one
|
|
6
|
-
// deliberate line — <AuthGate> — not the default. A signed-out visitor is
|
|
7
|
-
// bounced to the core portal's login (ADR-0007) and returned here afterwards;
|
|
8
|
-
// a signed-in visitor sees the content below.
|
|
9
|
-
//
|
|
10
|
-
// The render-prop form hands you the session, whose ID token you pass to THIS
|
|
11
|
-
// sibling's own backend via createApiClient (never the core API directly,
|
|
12
|
-
// ADR-0002). This example doesn't call the backend, but shows where the token
|
|
13
|
-
// comes from.
|
|
14
|
-
export default function ExampleMembersPage() {
|
|
15
|
-
return (
|
|
16
|
-
<AuthGate>
|
|
17
|
-
{(session) => (
|
|
18
|
-
<main className="center-screen">
|
|
19
|
-
<div>
|
|
20
|
-
<h1>Members only</h1>
|
|
21
|
-
<p>You're signed in — this rendered because a valid session exists.</p>
|
|
22
|
-
<p>
|
|
23
|
-
Your ID token (for calls to this sibling's backend) is{' '}
|
|
24
|
-
{session.getIdToken().getJwtToken().slice(0, 8)}…
|
|
25
|
-
</p>
|
|
26
|
-
</div>
|
|
27
|
-
</main>
|
|
28
|
-
)}
|
|
29
|
-
</AuthGate>
|
|
30
|
-
)
|
|
31
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import Link from 'next/link'
|
|
2
|
-
|
|
3
|
-
// A minimal PUBLIC page — the go-live default.
|
|
4
|
-
//
|
|
5
|
-
// There is no auth code here, and that is the whole point: anything you drop
|
|
6
|
-
// under src/app/ is served unauthenticated the moment it deploys. Delete this
|
|
7
|
-
// route once you've seen how it works, or copy it as the starting point for
|
|
8
|
-
// your own public content. To make a page private instead, wrap it in
|
|
9
|
-
// <AuthGate> — see ./members/page.tsx.
|
|
10
|
-
export default function ExamplePublicPage() {
|
|
11
|
-
return (
|
|
12
|
-
<main className="center-screen">
|
|
13
|
-
<div>
|
|
14
|
-
<h1>This page is public</h1>
|
|
15
|
-
<p>
|
|
16
|
-
Anyone can see it — no login, no redirect. This is how most of your app ships at go-live.
|
|
17
|
-
</p>
|
|
18
|
-
<p>
|
|
19
|
-
<Link href="/example/members/">See the same pattern, but auth-gated →</Link>
|
|
20
|
-
</p>
|
|
21
|
-
</div>
|
|
22
|
-
</main>
|
|
23
|
-
)
|
|
24
|
-
}
|