@sidebase/base-config 0.1.0 → 0.2.1

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.
@@ -1,18 +1,11 @@
1
- # Managed by streamctl (full-own, render: automation-upgrade). OFF BY DEFAULT: this
2
- # file only lands when a repo sets `automation: { upgradePr: true }` in
3
- # streamctl.config.ts. See the payload README "Upgrade-PR workflow" for enabling.
1
+ # Managed by streamctl. Off by default; lands only when a repo sets
2
+ # `automation: { upgradePr: true }`. See the README section "Upgrade-PR workflow".
4
3
  #
5
- # TOKEN: the PR is opened with `secrets.STREAMCTL_PR_TOKEN` (a GitHub App
6
- # installation token or a machine-account PAT), NOT the default `GITHUB_TOKEN`.
7
- # A PR created with `GITHUB_TOKEN` does NOT trigger `pull_request` workflows, so
8
- # this repo's own `check` gate would never run on the bot's PR. The bot identity
9
- # for the fleet is still being decided; treat this file as inert and provide the
10
- # secret before enabling. No registry token is needed: the payload is public npm.
11
- # A repo with OTHER private dependencies must opt this file out
12
- # (`files: { ".github/workflows/streamctl-upgrade.yml": "off" }`) and wire its own auth.
4
+ # Needs `secrets.STREAMCTL_PR_TOKEN`: a PR opened with `GITHUB_TOKEN` does not trigger
5
+ # `pull_request` workflows, so the repo's own `check` gate would never run on it.
13
6
  #
14
- # Actions are pinned by full commit SHA (this workflow handles a token); the version
15
- # tag is in the trailing comment.
7
+ # A repo with private dependencies must opt this file out and wire its own auth:
8
+ # `files: { ".github/workflows/streamctl-upgrade.yml": "off" }`.
16
9
  name: streamctl upgrade
17
10
 
18
11
  on:
@@ -20,8 +13,8 @@ on:
20
13
  - cron: "0 6 * * 1" # Mondays 06:00 UTC
21
14
  workflow_dispatch:
22
15
 
23
- # Least privilege: every PR/issue write below uses STREAMCTL_PR_TOKEN, so the
24
- # default token only needs to read the repo for checkout.
16
+ # Every PR and issue write below uses STREAMCTL_PR_TOKEN, so the default token
17
+ # only needs to read the repo for checkout.
25
18
  permissions:
26
19
  contents: read
27
20
 
@@ -32,9 +25,8 @@ jobs:
32
25
  upgrade:
33
26
  runs-on: ubuntu-latest
34
27
  steps:
35
- # A bot identity is REQUIRED for the PR (see the header). To mint an App token
36
- # in-workflow instead of storing a PAT, uncomment and wire the App credentials,
37
- # then use `${{ steps.bot.outputs.token }}` in place of STREAMCTL_PR_TOKEN below:
28
+ # To mint an App token in-workflow instead of storing a PAT, uncomment this
29
+ # and use `${{ steps.bot.outputs.token }}` in place of STREAMCTL_PR_TOKEN:
38
30
  #
39
31
  # - id: bot
40
32
  # uses: actions/create-github-app-token@5d869da34e18e7287c1daad50e0b8ea0f506ce69 # v1.11.0
@@ -59,8 +51,7 @@ jobs:
59
51
  - name: Install dependencies
60
52
  run: pnpm install --frozen-lockfile
61
53
 
62
- # Exit codes drive the branch: 4 = an update is available (proceed); 0 = up to
63
- # date (stop, no PR); 3 = the repo already has drift (open an issue, not a PR).
54
+ # Exit codes: 4 = update available, 0 = up to date, 3 = repo already drifted.
64
55
  - id: check
65
56
  name: Check for a payload update
66
57
  run: |
@@ -91,9 +82,8 @@ jobs:
91
82
  set -e
92
83
  cat streamctl-upgrade.json
93
84
 
94
- # exit 2 = the chained sync hit conflicts and ROLLED BACK. Re-run bumping only the
95
- # pin + devDependency (no sync) so the PR carries a reviewable diff a human then
96
- # reconciles with `streamctl sync --interactive`.
85
+ # Exit 2 means the sync hit conflicts and rolled back. Bump only the pin and
86
+ # devDependency so the PR carries a diff a human reconciles interactively.
97
87
  - name: Prepare a plan-only bump (interactive sync required)
98
88
  if: ${{ steps.upgrade.outputs.code == '2' }}
99
89
  run: pnpm streamctl upgrade --no-install --json > streamctl-upgrade.json
@@ -11,9 +11,10 @@ pglite-debug.log
11
11
  prisma/*.db
12
12
  prisma/migrations/dev
13
13
  .DS_Store
14
- # streamctl local scratch dirs/files (e.g. local.concept) stay untracked.
15
- local.*
16
- local.*/
17
- # CLAUDE.md is managed by streamctl; a user-global gitignore that ignores the
18
- # filename everywhere would silently untrack it. Force-allow it here.
14
+ # streamctl scratch. Root-anchored so `src/path/local.ts` stays tracked.
15
+ /local.*
16
+ /local.*/
17
+ prisma/local.*
18
+ # CLAUDE.md is managed by streamctl. A user-global gitignore matching the name
19
+ # everywhere would silently untrack it, so force-allow it.
19
20
  !CLAUDE.md
@@ -3,8 +3,9 @@
3
3
  "browser": true
4
4
  },
5
5
  "ignorePatterns": [
6
- "local.*",
7
- "local.*/"
6
+ "/local.*",
7
+ "/local.*/",
8
+ "prisma/local.*"
8
9
  ],
9
10
  "plugins": [
10
11
  "unicorn",
@@ -24,6 +25,7 @@
24
25
  "max-depth": "off",
25
26
  "max-nested-callbacks": "off",
26
27
  "max-lines": "off",
28
+ "no-underscore-dangle": "off",
27
29
  "no-warning-comments": "off",
28
30
  "no-inline-comments": "off",
29
31
  "no-map-spread": "off"
@@ -1,22 +1,15 @@
1
- # Managed by streamctl (full-own, render: security). pnpm's own settings file.
1
+ # Managed by streamctl. pnpm's own settings file.
2
2
  #
3
- # SUPPLY-CHAIN COOLDOWN: a version must have been published for ${MIN_RELEASE_AGE}
4
- # minutes before pnpm will resolve it, so a compromised release has time to be caught
5
- # and yanked before the fleet installs it. Requires pnpm >= 10.16 (baseline: 10.28.1);
6
- # it gates fresh resolution only, so `--frozen-lockfile` installs are unaffected.
7
- # `@sidebase/*` is exempt: the first-party scope (this payload + the streamctl CLI),
8
- # published by the org itself, so a payload release reaches the fleet the same day.
3
+ # Cooldown: a version must be ${MIN_RELEASE_AGE} minutes old before pnpm resolves it,
4
+ # giving a compromised release time to be yanked. Needs pnpm >= 10.16. Gates fresh
5
+ # resolution only, so `--frozen-lockfile` is unaffected. `@sidebase/*` is exempt.
9
6
  #
10
- # `packages: []` is REQUIRED, not decorative: pnpm defaults it to `**` whenever a
11
- # pnpm-workspace.yaml exists, which would silently promote every nested package.json
12
- # (test fixtures, examples) to a workspace project and break `--frozen-lockfile`.
13
- # A real monorepo owns this key itself, so opt the file out with
14
- # `files: { "pnpm-workspace.yaml": "off" }` in .streamctl/config.ts.
7
+ # `packages: []` is required: pnpm otherwise defaults it to `**`, promoting every nested
8
+ # package.json to a workspace project and breaking `--frozen-lockfile`. A monorepo should
9
+ # opt out with `files: { "pnpm-workspace.yaml": "off" }`.
15
10
  #
16
- # `onlyBuiltDependencies` is the postinstall-script allowlist: everything else installs
17
- # with its lifecycle scripts blocked. The baseline covers what the fleet universally
18
- # needs; add extras via `pnpm: { onlyBuiltDependencies: [...] }` rather than running
19
- # `pnpm approve-builds` (which writes here and would be reverted on the next sync).
11
+ # `onlyBuiltDependencies` allowlists postinstall scripts. Add extras through the `pnpm`
12
+ # knob, not `pnpm approve-builds`, which writes here and is reverted on the next sync.
20
13
  packages: []
21
14
  minimumReleaseAge: ${MIN_RELEASE_AGE}
22
15
  minimumReleaseAgeExclude:
@@ -3,11 +3,11 @@
3
3
  "files": [
4
4
  { "path": ".editorconfig", "strategy": "block", "source": "base/editorconfig", "blockMark": "editorconfig" },
5
5
  { "path": "tsconfig.json", "strategy": "full", "source": "base/tsconfig.json", "adoption": "expected" },
6
- { "path": ".dockerignore", "strategy": "full", "source": "base/dockerignore", "adoption": "expected" },
6
+ { "path": ".dockerignore", "strategy": "block", "source": "base/dockerignore", "blockMark": "dockerignore" },
7
7
  { "path": "pnpm-workspace.yaml", "strategy": "full", "source": "base/pnpm-workspace.yaml", "render": "security", "adoption": "expected" },
8
8
  { "path": ".gitignore", "strategy": "block", "source": "base/gitignore", "blockMark": "core" },
9
9
  { "path": ".oxlintrc.json", "strategy": "full", "source": "base/oxlintrc.json", "adoption": "expected" },
10
- { "path": ".vscode/settings.json", "strategy": "merge", "source": "base/vscode/settings.json", "projectFields": ["editor.fontSize", "editor.rulers", "editor.formatOnSave", "files.exclude", "search.exclude", "files.watcherExclude"] },
10
+ { "path": ".vscode/settings.json", "strategy": "merge", "source": "base/vscode/settings.json", "render": "editor", "projectFields": ["editor.fontSize", "editor.rulers", "editor.formatOnSave", "files.exclude", "search.exclude", "files.watcherExclude"] },
11
11
  { "path": ".vscode/extensions.json", "strategy": "merge", "source": "base/vscode/extensions.json", "projectFields": ["unwantedRecommendations"] },
12
12
  { "path": "AGENTS.md", "strategy": "full", "source": "base/AGENTS.md", "adoption": "expected" },
13
13
  { "path": "CLAUDE.md", "strategy": "scaffold", "source": "base/CLAUDE.md", "adoption": "expected" },
@@ -19,6 +19,11 @@
19
19
  "NODE_VERSION": { "configPath": "versions.node", "default": "24.13.0", "pattern": "^[\\w.+-]+$" }
20
20
  }
21
21
  },
22
+ "editor": {
23
+ "placeholders": {
24
+ "I18N_SOURCE_LANGUAGE": { "configPath": "editor.i18nSourceLanguage", "default": "de", "pattern": "^[a-z]{2,3}(-[A-Za-z0-9]{2,8})*$" }
25
+ }
26
+ },
22
27
  "security": {
23
28
  "placeholders": {
24
29
  "MIN_RELEASE_AGE": { "configPath": "security.minimumReleaseAge", "default": "10080", "pattern": "^\\d+$" }
@@ -30,6 +35,7 @@
30
35
  },
31
36
  "configKeys": {
32
37
  "automation.upgradePr": "boolean",
38
+ "editor.i18nSourceLanguage": "string",
33
39
  "security.minimumReleaseAge": "string",
34
40
  "pnpm.onlyBuiltDependencies": "string[]",
35
41
  "versions.node": "string",
@@ -39,5 +39,11 @@
39
39
  "toml",
40
40
  "gql",
41
41
  "graphql"
42
- ]
42
+ ],
43
+
44
+ // i18n-ally: the fleet standard is @nuxtjs/i18n with flat dotted keys in
45
+ // i18n/locales. sourceLanguage is the one field that varies, so it is a knob.
46
+ "i18n-ally.localesPaths": ["i18n/locales"],
47
+ "i18n-ally.keystyle": "flat",
48
+ "i18n-ally.sourceLanguage": "${I18N_SOURCE_LANGUAGE}"
43
49
  }
@@ -1,7 +1,7 @@
1
1
  import { defineNuxtBaseConfig } from '@sidebase/base-config'
2
2
 
3
- // Scaffolded by `streamctl init`. `defineNuxtBaseConfig` gives typed editor
4
- // inference for this payload's knobs; the CLI validates the file on every sync.
3
+ // Scaffolded by `streamctl init`. `defineNuxtBaseConfig` types the knobs below.
4
+ // The CLI validates this file on every sync.
5
5
  export default defineNuxtBaseConfig({
6
6
  package: '__PACKAGE__',
7
7
  base: '__BASE__',
@@ -9,10 +9,11 @@ export default defineNuxtBaseConfig({
9
9
  profile: '__PROFILE__',
10
10
 
11
11
  // Optional knobs, uncomment to enable:
12
- // ci: { unitTests: true, e2e: true },
12
+ // ci: { unitTests: true, e2e: true, aptPackages: ['libxml2-utils'] }, // apt extras for the test/e2e jobs
13
13
  // versions: { node: '24.13.0', pnpm: '10.28.1' },
14
14
  // docker: { aptPackages: ['ffmpeg'] }, // extras; openssl is always installed
15
15
  // security: { minimumReleaseAge: '10080' }, // minutes before pnpm installs a release; '0' disables
16
16
  // pnpm: { onlyBuiltDependencies: ['sharp'] }, // extras on top of prisma + esbuild
17
+ // editor: { i18nSourceLanguage: 'en' }, // i18n-ally source language (default: 'de')
17
18
  // eslint: { trpcGuard: true },
18
19
  })
@@ -1,5 +1,5 @@
1
1
  {
2
- "schemaVersion": 2,
2
+ "schemaVersion": 3,
3
3
  "presets": [
4
4
  "base",
5
5
  "nuxt-app"
@@ -5,24 +5,22 @@ ARG PNPM_VERSION=${PNPM_VERSION}
5
5
  # --- BUILD STAGE ---
6
6
  FROM $NODE_VERSION AS production-base
7
7
 
8
- # A pre-`FROM` ARG is visible only to `FROM`. Re-declare it bare to inherit the
9
- # global value inside this stage, or $PNPM_VERSION expands to empty below.
8
+ # A pre-`FROM` ARG is visible only to `FROM`. Re-declare it bare here, or
9
+ # $PNPM_VERSION expands to empty below and pnpm installs at latest.
10
10
  ARG PNPM_VERSION
11
11
 
12
12
  WORKDIR /app
13
13
 
14
- # Installed directly rather than through corepack: Node 25 no longer bundles
15
- # corepack, and `versions.node` declares no ceiling. npm's global bin is already
16
- # on PATH, so no PNPM_HOME wiring is needed.
14
+ # Not corepack: Node 25 no longer bundles it. npm's global bin is already on
15
+ # PATH, so this needs no PNPM_HOME wiring.
17
16
  RUN npm i -g pnpm@$PNPM_VERSION
18
17
 
19
18
  # Copy pnpm files
20
19
  COPY package.json pnpm-lock.yaml .npmrc* ./
21
20
  ${DOCKER_PRE_INSTALL}
22
- # load packages into the virtual store using only information from a lockfile.
23
- # --ignore-scripts: only package files exist at this layer, so lifecycle scripts
24
- # (e.g. `postinstall: nuxt prepare`) would run against no sources; the explicit
25
- # build steps below (docker.buildSteps) cover them against the full tree.
21
+ # --ignore-scripts: only package files exist at this layer, so a `postinstall`
22
+ # like `nuxt prepare` would run against no sources. The build steps below run it
23
+ # against the full tree instead.
26
24
  RUN pnpm install --ignore-scripts --frozen-lockfile --prefer-offline
27
25
 
28
26
  ARG ARG_NUXT_BUILD_CLIENT_SOURCE_MAPS=false
@@ -31,33 +29,30 @@ ${DOCKER_BUILD_ARGS}
31
29
  # copy the app, note .dockerignore
32
30
  COPY . .
33
31
 
34
- # split commands into seperate RUN to not invalidate entire cache layers
32
+ # split commands into separate RUN to not invalidate entire cache layers
35
33
  ${DOCKER_BUILD_STEPS}
36
34
 
37
35
  # --- FINAL PRODUCTION STAGE ---
38
36
  FROM $NODE_VERSION-slim AS production
39
37
 
40
- # openssl is always installed: the Prisma query engine generated in the build
41
- # stage (debian-openssl-3.0.x) dynamically links libssl3, which slim images do
42
- # not ship. Without it the app crashes on its first query. APT_PACKAGES adds
43
- # project-owned extras on top (docker.aptPackages knob, e.g. "ffmpeg").
38
+ # openssl is always installed: the Prisma query engine links libssl3, which slim
39
+ # images do not ship, and the app would crash on its first query without it.
40
+ # APT_PACKAGES adds project extras on top (docker.aptPackages).
44
41
  ARG APT_PACKAGES="${APT_PACKAGES}"
45
42
  RUN apt-get update && apt-get install -y --no-install-recommends openssl $APT_PACKAGES \
46
43
  && rm -rf /var/lib/apt/lists/*
47
44
 
48
- # copy necessary directories from the production-base stage to the final production
49
- # stage, owned by the runtime uid 1000 rather than root (see the USER switch below)
45
+ # Owned by uid 1000 so a future non-root switch needs no extra chown pass.
50
46
  COPY --chown=node:node --from=production-base /app/.output /app/.output
51
47
 
52
48
  WORKDIR /app
53
49
 
54
50
  ${DOCKER_PRISMA_RUNTIME}
55
51
  ${DOCKER_FINAL_STAGE}
56
- # Drop to the unprivileged `node` user (uid 1000) the base image already ships.
57
- # FIXED and outside every knob, so an override cannot re-root the container.
58
- # Everything the runtime reads or executes is node-owned, and `npm exec` writes
59
- # its npx cache under /home/node/.npm, which the official image creates writable.
60
- USER node
52
+ # The container stays root on purpose. A `USER node` switch here breaks any
53
+ # deployment that overrides the CMD with a command needing root: the prisma-studio
54
+ # pods apt-install postgresql-client on start, which fails as an unprivileged user.
55
+ # Set docker.finalStage to "USER node" to opt back in.
61
56
 
62
57
  # start the app
63
58
  CMD [ "sh", "-c", "${DOCKER_START_COMMAND}" ]
@@ -1,15 +1,14 @@
1
- # Managed by streamctl (full-own, render: ci). NODE_VERSION is a render knob
2
- # sourced from the version baseline. pnpm is not pinned here: action-setup reads
3
- # `packageManager` from package.json, the single reconciled source.
4
- # The build-and-deploy-* preview/staging/production suite is deferred to 0.2.0.
1
+ # Managed by streamctl (full-own, render: ci). Edits here are overwritten on sync.
2
+ # NODE_VERSION comes from the version baseline. pnpm is not pinned here because
3
+ # action-setup reads `packageManager` from package.json.
5
4
  name: CI
6
5
 
7
6
  on:
8
7
  pull_request:
9
8
  branches: [main]
10
9
 
11
- # Least privilege: the jobs only read the repo. Install/build steps run
12
- # third-party code, so a read-only default token limits a malicious script.
10
+ # The jobs only read the repo. Install and build run third-party code, so a
11
+ # read-only default token limits what a malicious package can do.
13
12
  permissions:
14
13
  contents: read
15
14
 
@@ -19,6 +18,9 @@ concurrency:
19
18
 
20
19
  env:
21
20
  NODE_VERSION: "${NODE_VERSION}"
21
+ # Extra apt packages for the test/e2e jobs (ci.aptPackages). Empty by default;
22
+ # the install step is skipped when unset.
23
+ CI_APT_PACKAGES: "${CI_APT_PACKAGES}"
22
24
 
23
25
  jobs:
24
26
  lint-typecheck:
@@ -5,8 +5,8 @@ on:
5
5
  types:
6
6
  - unlabeled
7
7
 
8
- # Default-deny at workflow level so any future job starts read-only; the
9
- # cleanup job below grants itself the exact write scopes it needs.
8
+ # Default-deny so any future job starts read-only. The cleanup job below grants
9
+ # itself the exact write scopes it needs.
10
10
  permissions:
11
11
  contents: read
12
12
 
@@ -28,14 +28,14 @@ jobs:
28
28
  const { owner, repo } = context.repo;
29
29
  const issue_number = context.issue.number;
30
30
 
31
- // check first if the label exists on the PR
32
- const { data: labels } = await github.rest.issues.listLabelsOnIssue({
33
- owner,
34
- repo,
35
- issue_number
36
- });
31
+ // check first if the label exists on the PR
32
+ const { data: labels } = await github.rest.issues.listLabelsOnIssue({
33
+ owner,
34
+ repo,
35
+ issue_number
36
+ });
37
37
 
38
- const hasPreviewDeployedLabel = labels.some(label => label.name === 'preview-deployed');
39
- if (hasPreviewDeployedLabel) {
40
- await github.rest.issues.removeLabel({ owner, repo, issue_number, name: 'preview-deployed'});
41
- }
38
+ const hasPreviewDeployedLabel = labels.some(label => label.name === 'preview-deployed');
39
+ if (hasPreviewDeployedLabel) {
40
+ await github.rest.issues.removeLabel({ owner, repo, issue_number, name: 'preview-deployed'});
41
+ }
@@ -12,6 +12,7 @@
12
12
  "renders": {
13
13
  "ci": {
14
14
  "placeholders": {
15
+ "CI_APT_PACKAGES": { "configPath": "ci.aptPackages", "default": "", "pattern": "^$|^[a-z0-9][a-z0-9 +.-]*$", "join": "space" },
15
16
  "NODE_VERSION": { "configPath": "versions.node", "default": "24.13.0", "pattern": "^[\\w.+-]+$" }
16
17
  },
17
18
  "fragments": [
@@ -28,7 +29,8 @@
28
29
  "DOCKER_BUILD_ARGS": { "configPath": "docker.buildArgs", "default": "" },
29
30
  "DOCKER_BUILD_STEPS": { "configPath": "docker.buildSteps", "default": "RUN pnpm nuxi prepare\nRUN pnpm prisma generate\nRUN pnpm run build" },
30
31
  "DOCKER_FINAL_STAGE": { "configPath": "docker.finalStage", "default": "" },
31
- "DOCKER_PRISMA_RUNTIME": { "configPath": "docker.prismaRuntime", "default": "COPY --chown=node:node --from=production-base /app/prisma /app/prisma\n\n# Prisma CLI version for `migrate deploy`. Defaults to the baseline; override with --build-arg.\nARG PRISMA_VERSION=6.19.1\n\n# install prisma to run the `migrate deploy`. Runs as root because /app is\n# root-owned from WORKDIR; hand the install output to the runtime user in the\n# same layer so no later chown duplicates node_modules.\nRUN npm i -D prisma@${PRISMA_VERSION} && chown -R node:node /app/node_modules" },
32
+ "DOCKER_PRISMA_RUNTIME": { "configPath": "docker.prismaRuntime", "default": "COPY --chown=node:node --from=production-base /app/prisma /app/prisma\n\n# Prisma CLI for `migrate deploy`. Override the pin with --build-arg.\nARG PRISMA_VERSION=${PRISMA_VERSION_DEFAULT}\n\n# Chowned to uid 1000 in the same layer, so a later USER switch needs no\n# second pass over node_modules.\nRUN npm i -D prisma@${PRISMA_VERSION} && chown -R node:node /app/node_modules" },
33
+ "PRISMA_VERSION_DEFAULT": { "configPath": "docker.prismaVersion", "fromDependency": "prisma", "default": "6.19.1", "pattern": "^\\d+\\.\\d+\\.\\d+(?:-[0-9A-Za-z.-]+)?$" },
32
34
  "DOCKER_START_COMMAND": { "configPath": "docker.startCommand", "default": "npm exec prisma migrate deploy && node --max-old-space-size-percentage=75 .output/server/index.mjs" }
33
35
  },
34
36
  "passthrough": ["PRISMA_VERSION"]
@@ -37,12 +39,14 @@
37
39
  "configKeys": {
38
40
  "ci.unitTests": "boolean",
39
41
  "ci.e2e": "boolean",
42
+ "ci.aptPackages": "string[]",
40
43
  "docker.aptPackages": "string[]",
41
44
  "docker.preInstall": "string",
42
45
  "docker.buildArgs": "string",
43
46
  "docker.buildSteps": "string",
44
47
  "docker.finalStage": "string",
45
48
  "docker.prismaRuntime": "string",
49
+ "docker.prismaVersion": "string",
46
50
  "docker.startCommand": "string",
47
51
  "eslint": "object"
48
52
  },
@@ -23,6 +23,9 @@
23
23
  --health-retries 5
24
24
  steps:
25
25
  - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
26
+ - name: Install apt packages
27
+ if: ${{ env.CI_APT_PACKAGES != '' }}
28
+ run: sudo apt-get update && sudo apt-get install -y --no-install-recommends $CI_APT_PACKAGES
26
29
  - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
27
30
  - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
28
31
  with:
@@ -31,9 +34,6 @@
31
34
  - run: pnpm install --frozen-lockfile
32
35
  # tests may import the generated Prisma client
33
36
  - run: pnpm prisma generate
34
- # Schema setup (db push / migrate) and seeding are left to the consumer's
35
- # test:e2e script on purpose: they are coupled to fixture seeding, which only
36
- # the app's own harness owns, and CI cannot guess the reset/migrate/seed
37
- # strategy. This job provides a healthy, reachable DB (DATABASE_URL above) and
38
- # the generated client; test:e2e must create and seed its own schema.
37
+ # This job provides a reachable DB and the generated client. Schema setup and
38
+ # seeding belong to test:e2e, which owns the fixture strategy CI cannot guess.
39
39
  - run: pnpm test:e2e
@@ -2,6 +2,9 @@
2
2
  runs-on: ubuntu-latest
3
3
  steps:
4
4
  - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
5
+ - name: Install apt packages
6
+ if: ${{ env.CI_APT_PACKAGES != '' }}
7
+ run: sudo apt-get update && sudo apt-get install -y --no-install-recommends $CI_APT_PACKAGES
5
8
  - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
6
9
  - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
7
10
  with: