@starci/hfs 4.4.0 → 4.5.0

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.
Files changed (113) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +1 -1
  3. package/ci/cli.mjs +64 -0
  4. package/ci/github.mjs +41 -0
  5. package/ci/secret.mjs +28 -0
  6. package/ci/vars.mjs +33 -0
  7. package/ci/verify.mjs +36 -0
  8. package/db/backup-receipt.mjs +129 -0
  9. package/db/dump.mjs +66 -0
  10. package/db/migrate.mjs +8 -5
  11. package/db/post-cutover.mjs +4 -4
  12. package/db/reset.mjs +125 -0
  13. package/emit/contracts.mjs +2 -2
  14. package/emit/db-types.mjs +100 -7
  15. package/lint/run.mjs +30 -8
  16. package/package.json +2 -1
  17. package/release/ci-red.mjs +70 -0
  18. package/release/gate.mjs +53 -13
  19. package/release/index.mjs +8 -6
  20. package/release/push.mjs +1 -1
  21. package/report/sonar.mjs +1 -1
  22. package/runtime/config.example.yaml +7 -6
  23. package/runtime/engine/config.mjs +10 -18
  24. package/runtime/engine/removed-vocabulary.mjs +0 -2
  25. package/runtime/knowledge/hfs/canon-pins.yaml +4 -4
  26. package/runtime/knowledge/hfs/rules.yaml +505 -971
  27. package/runtime/knowledge/hfs/slots.yaml +13 -24
  28. package/runtime/modules/kernel/failure-codes.yaml +60 -22
  29. package/runtime/modules/kernel/removed-vocabulary.yaml +30 -0
  30. package/runtime/modules/models/runtimes.yaml +4 -6
  31. package/runtime/modules/schemas/application-stacks.schema.yaml +131 -1
  32. package/runtime/packages/cli/src/catalog.generated.mjs +286 -398
  33. package/runtime/scripts/api/git/lib.mjs +3 -3
  34. package/runtime/scripts/api/sops/lib.mjs +1 -1
  35. package/runtime/scripts/hfs/app-wiring.mjs +2 -2
  36. package/runtime/scripts/hfs/architecture/config.mjs +1 -1
  37. package/runtime/scripts/hfs/architecture/index.mjs +1 -1
  38. package/runtime/scripts/hfs/architecture/supabase.mjs +1 -1
  39. package/runtime/scripts/hfs/architecture/tiers.mjs +1 -1
  40. package/runtime/scripts/hfs/architecture.mjs +1 -1
  41. package/runtime/scripts/hfs/ci-declaration.mjs +102 -0
  42. package/runtime/scripts/hfs/coverage-from.mjs +1 -1
  43. package/runtime/scripts/hfs/coverage-scope.mjs +1 -1
  44. package/runtime/scripts/hfs/example-secrets.mjs +1 -1
  45. package/runtime/scripts/hfs/manifest-shape.mjs +3 -3
  46. package/runtime/scripts/hfs/param-names.mjs +1 -1
  47. package/runtime/scripts/hfs/rule-catalog.mjs +3 -1
  48. package/runtime/scripts/hfs/rules/a15-findings.mjs +10 -1
  49. package/runtime/scripts/hfs/rules/app-workflow-findings.mjs +10 -0
  50. package/runtime/scripts/hfs/rules/assets.mjs +1 -1
  51. package/runtime/scripts/hfs/rules/ci-custody.mjs +104 -0
  52. package/runtime/scripts/hfs/rules/cli.mjs +1 -1
  53. package/runtime/scripts/hfs/rules/contract-compat.mjs +1 -1
  54. package/runtime/scripts/hfs/rules/contract.mjs +1 -1
  55. package/runtime/scripts/hfs/rules/deploy-workflow.mjs +6 -19
  56. package/runtime/scripts/hfs/rules/fe-build-args.mjs +142 -0
  57. package/runtime/scripts/hfs/rules/frontend-tree.mjs +2 -2
  58. package/runtime/scripts/hfs/rules/supabase-secrets.mjs +1 -1
  59. package/runtime/scripts/hfs/rules/supply-chain.mjs +40 -3
  60. package/runtime/scripts/hfs/rules/workflow-contexts.mjs +103 -0
  61. package/runtime/scripts/hfs/runtime-rules/workflow-source.mjs +2 -2
  62. package/runtime/scripts/hfs/slots.mjs +2 -2
  63. package/runtime/scripts/hfs/typescript-programs.mjs +0 -8
  64. package/runtime/scripts/lib/env.mjs +2 -2
  65. package/runtime/scripts/lib/git.mjs +1 -1
  66. package/runtime/scripts/lib/i18n.mjs +0 -2
  67. package/runtime/scripts/lib/language.mjs +1 -1
  68. package/runtime/scripts/lib/roots.mjs +2 -4
  69. package/runtime/scripts/lib/secret-patterns.mjs +2 -2
  70. package/scaffold/add-fe-overlay.mjs +0 -121
  71. package/scaffold/add-fe-page.mjs +0 -268
  72. package/scaffold/supabase-ports.mjs +1 -1
  73. package/src/main.mjs +17 -6
  74. package/stack/age-install.mjs +1 -1
  75. package/stack/cli.mjs +2 -2
  76. package/stack/context.mjs +14 -2
  77. package/stack/digest.mjs +1 -1
  78. package/stack/docker-transport.mjs +93 -15
  79. package/stack/edge-alias.mjs +1 -1
  80. package/stack/image-scan.mjs +1 -1
  81. package/stack/ingress-create.mjs +2 -2
  82. package/stack/ingress.mjs +3 -3
  83. package/stack/release-store.mjs +12 -7
  84. package/stack/remote.mjs +16 -8
  85. package/stack/sealed.mjs +5 -5
  86. package/stack/ssh-session.mjs +178 -0
  87. package/sync/ci-commands.mjs +103 -1
  88. package/sync/format.mjs +1 -1
  89. package/sync/hygiene.mjs +1 -1
  90. package/sync/index.mjs +43 -18
  91. package/sync/quality-services.mjs +61 -0
  92. package/sync/readme-badges.mjs +44 -0
  93. package/sync/stack-images.mjs +31 -5
  94. package/templates/app/ci-workflows/github/workflows/ci.yml +26 -24
  95. package/templates/app/ci-workflows/github/workflows/images.yml +24 -2
  96. package/templates/app/ci-workflows/github/workflows/stack-deploy.yml +8 -2
  97. package/templates/app/ci-workflows/install-steps.yml +21 -0
  98. package/templates/app/ci-workflows/sonar-steps.yml +3 -9
  99. package/templates/app/ci-workflows-lite/github/workflows/ci.yml +28 -35
  100. package/templates/app/ci-workflows-lite/github/workflows/db-deploy.yml +2 -1
  101. package/templates/app/ci-workflows-lite/github/workflows/images.yml +24 -2
  102. package/templates/app/ci-workflows-lite/github/workflows/stack-deploy.yml +8 -2
  103. package/templates/app/quality-config/codecov.yml +6 -6
  104. package/templates/app/quality-config/sonar-project.properties +1 -0
  105. package/templates/app/readme-badges/README.md +1 -0
  106. package/templates/app/skeleton/.github/dependabot.yml +1 -14
  107. package/templates/app/skeleton/.starcistacks/application-stacks.yaml +61 -3
  108. package/templates/app/skeleton/README.md +6 -0
  109. package/templates/app/skeleton-lite/.github/dependabot.yml +1 -14
  110. package/templates/app/skeleton-lite/.starcistacks/application-stacks.yaml +57 -3
  111. package/templates/app/skeleton-lite/README.md +6 -0
  112. package/templates/app/upgrade-full/.starcistacks/application-stacks.yaml +52 -1
  113. package/upgrade/index.mjs +1 -1
@@ -9,68 +9,61 @@ on:
9
9
  permissions:
10
10
  contents: read
11
11
 
12
- # One run per ref.
12
+ # One run per ref: a release tag is never cancelled by another run.
13
13
  concurrency:
14
14
  group: ci-${{ github.ref }}
15
15
  cancel-in-progress: false
16
16
 
17
17
  jobs:
18
- ci:
18
+ fast:
19
19
  runs-on: ubuntu-latest
20
- # id-token: write lets the Codecov upload authenticate with GitHub's OIDC token: no repository secret, no silent skip.
21
- permissions:
22
- contents: read
23
- id-token: write
24
- env:
25
- SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
20
+ {{sonarEnv}}
26
21
  steps:
27
- - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
28
- - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
29
- with:
30
- node-version: {{nodeMajor}}
31
- cache: npm
32
- - run: npm ci --ignore-scripts
22
+ {{> app/ci-workflows/install-steps.yml}}
33
23
  - name: production dependency audit
34
- run: npm audit --omit=dev --audit-level=high
35
- - name: lint
36
- if: env.SONAR_TOKEN == ''
37
- run: {{ciLint}}
38
- - name: lint with Sonar import
39
- if: env.SONAR_TOKEN != ''
40
- run: {{ciLintSonar}}
24
+ run: {{auditCommand}}
25
+ {{ciLintSteps}}
41
26
  - name: format
42
27
  run: npm run format:check
43
28
  - name: typecheck
44
29
  run: npm run typecheck
30
+
31
+ test:
32
+ runs-on: ubuntu-latest
33
+ # Codecov OIDC authentication requires a job-scoped identity token.
34
+ permissions:
35
+ contents: read
36
+ id-token: write
37
+ steps:
38
+ {{> app/ci-workflows/install-steps.yml}}
45
39
  - name: unit
46
40
  run: npm test -- --ci
47
41
  - name: coverage proof
48
42
  run: {{ciCoverageProof}}
49
- - name: coverage upload
50
- uses: codecov/codecov-action@0fb7174895f61a3b6b78fc075e0cd60383518dac # v5.5.5
51
- if: ${{ !cancelled() && startsWith(github.ref, 'refs/tags/v') }}
43
+ - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
44
+ if: always() && hashFiles('{{lcovReport}}') != ''
52
45
  with:
53
- use_oidc: true
54
- files: {{lcovReport}}
55
- disable_search: true
56
- fail_ci_if_error: true
46
+ name: {{lcovArtifact}}
47
+ path: {{lcovReport}}
48
+ {{codecovSteps}}
49
+
50
+ build:
51
+ runs-on: ubuntu-latest
52
+ steps:
53
+ {{> app/ci-workflows/install-steps.yml}}
57
54
  - name: build be
58
55
  run: npm run build:be
59
56
  - name: build fe
60
57
  run: npm run build:fe
61
58
  - name: database migration checks
62
59
  run: {{ciDatabaseLint}}
63
- {{> app/ci-workflows/sonar-steps.yml}}
60
+
61
+ {{sonarJob}}
64
62
 
65
63
  db-types:
66
64
  runs-on: ubuntu-latest
67
65
  steps:
68
- - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
69
- - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
70
- with:
71
- node-version: {{nodeMajor}}
72
- cache: npm
73
- - run: npm ci --ignore-scripts
66
+ {{> app/ci-workflows/install-steps.yml}}
74
67
  - name: start Supabase
75
68
  run: npm run db:start
76
69
  - name: apply migrations
@@ -28,7 +28,6 @@ jobs:
28
28
  STACK_ENVIRONMENT: ${{ inputs.environment }}
29
29
  BACKUP_RECEIPT: ${{ inputs.backup_receipt }}
30
30
  SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY }}
31
- XDG_DATA_HOME: ${{ runner.temp }}/starci-data
32
31
  steps:
33
32
  - name: require release tag
34
33
  shell: bash
@@ -46,6 +45,8 @@ jobs:
46
45
  with:
47
46
  version: v3.13.2
48
47
  - name: materialize sealed custody and push migrations
48
+ env:
49
+ XDG_DATA_HOME: ${{ runner.temp }}/starci-data
49
50
  shell: bash
50
51
  run: |
51
52
  set -euo pipefail
@@ -17,21 +17,43 @@ concurrency:
17
17
 
18
18
  jobs:
19
19
  image:
20
- runs-on: ubuntu-latest
20
+ runs-on: ubuntu-latest{{imageJobEnvironment}}
21
+ env:
22
+ STACK_ENVIRONMENT: {{imageEnvironment}}
21
23
  strategy:
22
24
  fail-fast: false
23
25
  matrix:
24
26
  include:
25
27
  {{imageMatrix}}
26
- steps:
28
+ steps:{{imageEnvironmentGuard}}
27
29
  - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
28
30
  - name: release tag matches package version
29
31
  run: node -e "const version=require('./package.json').version;if(process.env.GITHUB_REF_NAME!=='v'+version)process.exit(1)"
32
+ - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
33
+ if: {{imageBuildArgsIf}}
34
+ with:
35
+ node-version: {{nodeMajor}}
36
+ cache: npm
37
+ - run: npm ci --ignore-scripts
38
+ if: {{imageBuildArgsIf}}
39
+ - name: install SOPS
40
+ if: {{imageBuildArgsIf}}
41
+ uses: mdgreenwald/mozilla-sops-action@bb2d96a13ef438ad122e5827a57ebd75d6ff118d # v2.1.0
42
+ with:
43
+ version: v3.13.2
44
+ - name: public build values
45
+ id: args
46
+ if: {{imageBuildArgsIf}}
47
+ env:
48
+ SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY }}
49
+ IMAGE_APP: ${{ matrix.name }}
50
+ run: npx --no-install starci app stack build-args --env "$STACK_ENVIRONMENT" --app "$IMAGE_APP"
30
51
  - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
31
52
  - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
32
53
  with:
33
54
  context: .
34
55
  file: ${{ matrix.file }}
56
+ build-args: ${{ steps.args.outputs.args }}
35
57
  push: false
36
58
  tags: {{imageProject}}/${{ matrix.name }}:${{ github.ref_name }}
37
59
  # OCI keeps the SBOM and provenance attestations without publishing to a registry.
@@ -50,7 +50,6 @@ jobs:
50
50
  packages: write
51
51
  env:
52
52
  STACK_ENVIRONMENT: ${{ inputs.environment }}
53
- XDG_DATA_HOME: ${{ runner.temp }}/starci-data
54
53
  steps:{{stackGuard}}
55
54
  - name: require release tag
56
55
  shell: bash
@@ -80,6 +79,7 @@ jobs:
80
79
  password: ${{ github.token }}{{stackImageSteps}}
81
80
  - name: connect to the swarm manager
82
81
  env:
82
+ XDG_DATA_HOME: ${{ runner.temp }}/starci-data
83
83
  VPS_SSH_KEY: ${{ secrets.VPS_SSH_KEY }}
84
84
  VPS_KNOWN_HOSTS: ${{ secrets.VPS_KNOWN_HOSTS }}
85
85
  VPS_HOST: ${{ vars.VPS_HOST }}
@@ -87,11 +87,14 @@ jobs:
87
87
  run: npx --no-install starci app stack connect --env "$STACK_ENVIRONMENT" --execute
88
88
  - name: deploy the release
89
89
  env:
90
+ XDG_DATA_HOME: ${{ runner.temp }}/starci-data
90
91
  SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY }}{{stackImageEnv}}{{stackPassEnv}}
91
92
  run: |
92
93
  npx --no-install starci app stack deploy --env "$STACK_ENVIRONMENT" \{{stackImageArgs}}
93
94
  --source-sha "$GITHUB_SHA" --execute
94
95
  - name: disconnect from the swarm manager
96
+ env:
97
+ XDG_DATA_HOME: ${{ runner.temp }}/starci-data
95
98
  if: ${{ always() }}
96
99
  run: npx --no-install starci app stack disconnect --env "$STACK_ENVIRONMENT" --execute
97
100
 
@@ -105,7 +108,6 @@ jobs:
105
108
  packages: read
106
109
  env:
107
110
  STACK_ENVIRONMENT: ${{ inputs.environment }}
108
- XDG_DATA_HOME: ${{ runner.temp }}/starci-data
109
111
  steps:
110
112
  - name: require release tag
111
113
  shell: bash
@@ -129,6 +131,7 @@ jobs:
129
131
  password: ${{ github.token }}
130
132
  - name: connect to the swarm manager
131
133
  env:
134
+ XDG_DATA_HOME: ${{ runner.temp }}/starci-data
132
135
  VPS_SSH_KEY: ${{ secrets.VPS_SSH_KEY }}
133
136
  VPS_KNOWN_HOSTS: ${{ secrets.VPS_KNOWN_HOSTS }}
134
137
  VPS_HOST: ${{ vars.VPS_HOST }}
@@ -136,6 +139,7 @@ jobs:
136
139
  run: npx --no-install starci app stack connect --env "$STACK_ENVIRONMENT" --execute
137
140
  - name: redeploy the stored release
138
141
  env:
142
+ XDG_DATA_HOME: ${{ runner.temp }}/starci-data
139
143
  SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY }}
140
144
  RELEASE: ${{ inputs.release }}
141
145
  shell: bash
@@ -144,5 +148,7 @@ jobs:
144
148
  [ -z "$RELEASE" ] || release=(--release "$RELEASE")
145
149
  npx --no-install starci app stack rollback --env "$STACK_ENVIRONMENT" "${release[@]}" --execute
146
150
  - name: disconnect from the swarm manager
151
+ env:
152
+ XDG_DATA_HOME: ${{ runner.temp }}/starci-data
147
153
  if: ${{ always() }}
148
154
  run: npx --no-install starci app stack disconnect --env "$STACK_ENVIRONMENT" --execute
@@ -1,21 +1,21 @@
1
1
  {{header}}
2
2
  # The be unit run's lcov ({{lcovReport}}), uploaded by the managed CI workflow. Coverage is the logic of be/src/modules/**: the status
3
3
  # paths are the measured roots of the one coverage scope (derived from the slot manifest's `coverage` field; its complement is rendered into
4
- # sonar.coverage.exclusions and its roots into be/jest.config.js), held at 100 on the project and on the patch, and each component (one per
5
- # service app, plus platform) is held at 100 too. fe/ and be/src/features are outside coverage (features are thin by rule; a front end has no tests).
4
+ # sonar.coverage.exclusions and its roots into be/jest.config.js), held at {{codecovTarget}} on the project and on the patch, and each component (one per
5
+ # service app, plus platform) is held at {{codecovTarget}} too. fe/ and be/src/features are outside coverage (features are thin by rule; a front end has no tests).
6
6
  codecov:
7
7
  require_ci_to_pass: true
8
8
  coverage:
9
9
  status:
10
10
  project:
11
11
  default:
12
- target: 100%
12
+ target: {{codecovTarget}}%
13
13
  threshold: 0%
14
14
  paths:
15
15
  {{codecovPaths}}
16
16
  patch:
17
17
  default:
18
- target: 100%
18
+ target: {{codecovTarget}}%
19
19
  threshold: 0%
20
20
  paths:
21
21
  {{codecovPaths}}
@@ -23,10 +23,10 @@ component_management:
23
23
  default_rules:
24
24
  statuses:
25
25
  - type: project
26
- target: 100%
26
+ target: {{codecovTarget}}%
27
27
  threshold: 0%
28
28
  - type: patch
29
- target: 100%
29
+ target: {{codecovTarget}}%
30
30
  threshold: 0%
31
31
  individual_components:
32
32
  {{codecovComponents}}
@@ -1,4 +1,5 @@
1
1
  {{> app/quality-config/sonar-base.properties}}
2
+ {{sonarHostLine}}
2
3
  sonar.tests=be/apps,be/src
3
4
  sonar.exclusions={{sonarExclusions}}
4
5
  sonar.test.inclusions=**/*.spec.ts
@@ -0,0 +1 @@
1
+ {{readmeBadges}}
@@ -1,17 +1,4 @@
1
1
  {{header}}
2
2
  version: 2
3
3
  updates:
4
- - package-ecosystem: npm
5
- directory: /
6
- schedule:
7
- interval: weekly
8
- - package-ecosystem: github-actions
9
- directory: /
10
- schedule:
11
- interval: weekly
12
- - package-ecosystem: docker
13
- directories:
14
- - /be/apps/*
15
- - /fe/apps/*
16
- schedule:
17
- interval: weekly
4
+ {{dependabotUpdates}}
@@ -1,6 +1,8 @@
1
1
  # The app declares its topology before any owner provisions a deployment.
2
2
  # All-zero application digests are illustrative and must be replaced by verified release digests.
3
3
  schema: starci/application-stacks@1
4
+ # To render README badges, declare ci.github: {repository: owner/repo, defaultBranch: main}.
5
+ # A GitHub package.json repository URL also enables the managed block.
4
6
  sources:
5
7
  - repository: "{{project}}"
6
8
  backing:
@@ -104,8 +106,15 @@ environments:
104
106
  app: core
105
107
  app:
106
108
  app: app
109
+ # Public browser configuration; replace the placeholder origin before deployment.
110
+ buildArgs:
111
+ values:
112
+ NEXT_PUBLIC_SITE_URL: "https://{{project}}.example.invalid"
107
113
  landing:
108
114
  app: landing
115
+ buildArgs:
116
+ values:
117
+ NEXT_PUBLIC_APP_URL: "https://{{project}}.example.invalid"
109
118
  volumes:
110
119
  - {{project}}-production-ingress-data
111
120
  - {{project}}-production-ingress-config-data
@@ -126,19 +135,68 @@ environments:
126
135
  k8s:
127
136
  status: deferred
128
137
  reason: This starter declares Docker Swarm production; no Kubernetes environment is provisioned.
138
+ ci:
139
+ secrets:
140
+ - {name: SONAR_TOKEN, scope: repository, purpose: Sonar analysis token provisioned for this app, optional: true}
141
+ - {name: SOPS_AGE_KEY, scope: environment, environment: production, purpose: Decrypt app members during deployment, optional: true}
142
+ - {name: VPS_SSH_KEY, scope: environment, environment: production, purpose: Deployment SSH key, optional: true}
143
+ - {name: VPS_KNOWN_HOSTS, scope: environment, environment: production, purpose: Pinned deployment SSH host keys, optional: true}
144
+ vars:
145
+ - {name: SONAR_HOST_URL, scope: repository, value: "https://sonar.{{project}}.example.invalid", purpose: Documentation endpoint to replace with this app's public Sonar host, optional: true}
146
+ - {name: VPS_HOST, scope: environment, environment: production, value: 203.0.113.10, purpose: Documentation deployment address to replace before use, optional: true}
147
+ - {name: VPS_USER, scope: environment, environment: production, value: deploy, purpose: Documentation deployment user to replace before use, optional: true}
129
148
  services:
130
149
  sonar:
131
150
  provider: sonarqube
132
151
  mode: local
133
152
  qualityGate: {{sonarGate}}
134
- host: { local: http://127.0.0.1:9000 }
153
+ host: {local: http://127.0.0.1:9000, public: "https://sonar.{{project}}.example.invalid"}
135
154
  stack:
136
155
  owner: host
137
156
  root: .claude/ext/sonar
138
157
  environment: dev
139
158
  compose: compose.yaml
140
159
  auth: token
141
- ci: { wiring: optional-follow-up }
160
+ credentials: []
161
+ projects: [{repository: "{{project}}", key: "{{project}}"}]
162
+ ci: {wiring: optional-follow-up, workflow: .github/workflows/ci.yml, token: SONAR_TOKEN, hostVar: SONAR_HOST_URL}
142
163
  ownerAction:
143
- needed: Provision the shared host Sonar project and its analysis credential through sealed custody.
164
+ needed: Provision this app's Sonar host and project, then set SONAR_TOKEN with starci app ci secret set and sync SONAR_HOST_URL.
144
165
  reason: A fresh app declares its quality service without fabricating credentials or a successful analysis.
166
+ codecov:
167
+ provider: codecov
168
+ mode: hosted
169
+ purpose: Report application coverage through GitHub OIDC.
170
+ auth: oidc
171
+ target: 100
172
+ components: auto
173
+ required: true
174
+ ci: {wiring: optional-follow-up, workflow: .github/workflows/ci.yml}
175
+ ownerAction: none
176
+ dependabot:
177
+ provider: github
178
+ mode: hosted
179
+ purpose: Keep application dependencies and workflow actions current.
180
+ ecosystems: [npm, docker, github-actions]
181
+ schedule: {interval: weekly}
182
+ groups: {minorPatch: grouped, major: per-package}
183
+ ignore: ['@starci/*']
184
+ security: immediate
185
+ ownerAction: none
186
+ audit:
187
+ provider: npm
188
+ mode: local
189
+ purpose: Refuse high severity production dependency vulnerabilities.
190
+ level: high
191
+ omitDev: true
192
+ in: [release-gate, ci]
193
+ ownerAction: none
194
+ container-registry:
195
+ provider: ghcr
196
+ mode: hosted
197
+ purpose: Publish this app's deployment images with the workflow GitHub token.
198
+ host: {public: https://ghcr.io}
199
+ auth: github-token
200
+ projects: [{repository: "{{project}}", key: "{{project}}"}]
201
+ ci: {wiring: optional-follow-up}
202
+ ownerAction: none
@@ -16,6 +16,10 @@ TypeScript everywhere; NestJS in `be/`, Next.js with next-intl in `fe/`; npm wit
16
16
  - `fe/`: the front end, one Next app per `fe/apps/<app>` and the shared workspace packages under `fe/packages/` (the ui drawings and the next-intl stack both apps call).
17
17
  - `scripts/`: the app's operational scripts; `hfs.json` declares both sides.
18
18
 
19
+ ## Status badges
20
+
21
+ Declare `ci.github.repository` and `ci.github.defaultBranch` in `.starcistacks/application-stacks.yaml` (or set the GitHub `repository` URL in `package.json`), then run `npx starci app sync --write`. Sync inserts a managed badge block after the title; `npx starci app sync --check` verifies it.
22
+
19
23
  ## Development
20
24
 
21
25
  ```sh
@@ -33,6 +37,8 @@ requests) and `PRIMARY_DB_URL` at boot; every door is closed until it is marked
33
37
  `npm run cli -- seed run` runs the dev seeds of `.starcistacks/dev/seeds` (run both from the app root). The product app reads
34
38
  `NEXT_PUBLIC_SITE_URL` and `NEXT_PUBLIC_GRAPHQL_URL` (the back end it calls through `fe/apps/app/src/modules/api`, read once the first GraphQL operation exists), the landing `NEXT_PUBLIC_APP_URL` (the product app it hands the reader over to). A missing key stops the process with an error that names it.
35
39
 
40
+ Production browser build values live in `.starcistacks/application-stacks.yaml` under `environments.production.deploy.images.*.buildArgs.values`. Replace the placeholder origins for the product's `NEXT_PUBLIC_SITE_URL` and the landing's `NEXT_PUBLIC_APP_URL` with your product app's public origin before building deployment images.
41
+
36
42
  ## Work
37
43
 
38
44
  The product's Work records live in `.starciwork`.
@@ -1,17 +1,4 @@
1
1
  {{header}}
2
2
  version: 2
3
3
  updates:
4
- - package-ecosystem: npm
5
- directory: /
6
- schedule:
7
- interval: weekly
8
- - package-ecosystem: github-actions
9
- directory: /
10
- schedule:
11
- interval: weekly
12
- - package-ecosystem: docker
13
- directories:
14
- - /be/apps/*
15
- - /fe/apps/*
16
- schedule:
17
- interval: weekly
4
+ {{dependabotUpdates}}
@@ -2,6 +2,8 @@
2
2
  # The source models declare intended compute; they prove no completed deployment.
3
3
  # All-zero application digests are illustrative and must be replaced by verified release digests.
4
4
  schema: starci/application-stacks@1
5
+ # To render README badges, declare ci.github: {repository: owner/repo, defaultBranch: main}.
6
+ # A GitHub package.json repository URL also enables the managed block.
5
7
  sources:
6
8
  - repository: {{project}}
7
9
  backing:
@@ -145,9 +147,12 @@ environments:
145
147
  app: api
146
148
  web:
147
149
  app: web
150
+ # Public browser configuration; replace these placeholders before deployment.
148
151
  buildArgs:
149
152
  values:
150
153
  NEXT_PUBLIC_SITE_URL: "https://{{project}}.example.invalid"
154
+ NEXT_PUBLIC_SUPABASE_URL: "https://supabase.{{project}}.example.invalid"
155
+ NEXT_PUBLIC_SUPABASE_ANON_KEY: "REPLACE_WITH_PUBLIC_SUPABASE_ANON_KEY"
151
156
  volumes:
152
157
  - {{project}}-production-ingress-data
153
158
  - {{project}}-production-ingress-config-data
@@ -175,19 +180,68 @@ environments:
175
180
  k8s:
176
181
  status: deferred
177
182
  reason: Lite production uses Docker Swarm with managed Supabase backing; Kubernetes belongs to a future full-edition deployment.
183
+ ci:
184
+ secrets:
185
+ - {name: SONAR_TOKEN, scope: repository, purpose: Sonar analysis token provisioned for this app, optional: true}
186
+ - {name: SOPS_AGE_KEY, scope: environment, environment: production, purpose: Decrypt app members during deployment, optional: true}
187
+ - {name: VPS_SSH_KEY, scope: environment, environment: production, purpose: Deployment SSH key, optional: true}
188
+ - {name: VPS_KNOWN_HOSTS, scope: environment, environment: production, purpose: Pinned deployment SSH host keys, optional: true}
189
+ vars:
190
+ - {name: SONAR_HOST_URL, scope: repository, value: "https://sonar.{{project}}.example.invalid", purpose: Documentation endpoint to replace with this app's public Sonar host, optional: true}
191
+ - {name: VPS_HOST, scope: environment, environment: production, value: 203.0.113.10, purpose: Documentation deployment address to replace before use, optional: true}
192
+ - {name: VPS_USER, scope: environment, environment: production, value: deploy, purpose: Documentation deployment user to replace before use, optional: true}
178
193
  services:
179
194
  sonar:
180
195
  provider: sonarqube
181
196
  mode: local
182
197
  qualityGate: {{sonarGate}}
183
- host: {local: http://127.0.0.1:9000}
198
+ host: {local: http://127.0.0.1:9000, public: "https://sonar.{{project}}.example.invalid"}
184
199
  stack:
185
200
  owner: host
186
201
  root: .claude/ext/sonar
187
202
  environment: dev
188
203
  compose: compose.yaml
189
204
  auth: token
190
- ci: {wiring: optional-follow-up}
205
+ credentials: []
206
+ projects: [{repository: "{{project}}", key: "{{project}}"}]
207
+ ci: {wiring: optional-follow-up, workflow: .github/workflows/ci.yml, token: SONAR_TOKEN, hostVar: SONAR_HOST_URL}
191
208
  ownerAction:
192
- needed: Provision the shared host Sonar project and its analysis credential through sealed custody.
209
+ needed: Provision this app's Sonar host and project, then set SONAR_TOKEN with starci app ci secret set and sync SONAR_HOST_URL.
193
210
  reason: A fresh app declares its quality service without fabricating credentials or a successful analysis.
211
+ codecov:
212
+ provider: codecov
213
+ mode: hosted
214
+ purpose: Report application coverage through GitHub OIDC.
215
+ auth: oidc
216
+ target: 100
217
+ components: auto
218
+ required: true
219
+ ci: {wiring: optional-follow-up, workflow: .github/workflows/ci.yml}
220
+ ownerAction: none
221
+ dependabot:
222
+ provider: github
223
+ mode: hosted
224
+ purpose: Keep application dependencies and workflow actions current.
225
+ ecosystems: [npm, docker, github-actions]
226
+ schedule: {interval: weekly}
227
+ groups: {minorPatch: grouped, major: per-package}
228
+ ignore: ['@starci/*']
229
+ security: immediate
230
+ ownerAction: none
231
+ audit:
232
+ provider: npm
233
+ mode: local
234
+ purpose: Refuse high severity production dependency vulnerabilities.
235
+ level: high
236
+ omitDev: true
237
+ in: [release-gate, ci]
238
+ ownerAction: none
239
+ container-registry:
240
+ provider: ghcr
241
+ mode: hosted
242
+ purpose: Publish this app's deployment images with the workflow GitHub token.
243
+ host: {public: https://ghcr.io}
244
+ auth: github-token
245
+ projects: [{repository: "{{project}}", key: "{{project}}"}]
246
+ ci: {wiring: optional-follow-up}
247
+ ownerAction: none
@@ -18,6 +18,10 @@ TypeScript everywhere, NestJS in `be/`, Next.js with next-intl in `fe/`, Supabas
18
18
  - `.starcistacks/`: value-free environment metadata and encrypted-secret custody.
19
19
  - `.starciwork/`: `.gitignore`, `.starciwork/workspace.yaml` project metadata and repo roles, and optional brand drawing records, references, and assets.
20
20
 
21
+ ## Status badges
22
+
23
+ Declare `ci.github.repository` and `ci.github.defaultBranch` in `.starcistacks/application-stacks.yaml` (or set the GitHub `repository` URL in `package.json`), then run `npx starci app sync --write`. Sync inserts a managed badge block after the title; `npx starci app sync --check` verifies it.
24
+
21
25
  ## Development
22
26
 
23
27
  ```sh
@@ -32,6 +36,8 @@ npm run build:fe
32
36
 
33
37
  The API reads `PORT`, `HTTP_SECURITY_ALLOWED_ORIGINS`, `PRIMARY_DB_URL`, `PRIMARY_DB_SCHEMA`, `SUPABASE_URL`, and `SUPABASE_SERVICE_ROLE_KEY`. The web app reads `NEXT_PUBLIC_SITE_URL`, `NEXT_PUBLIC_SUPABASE_URL`, `NEXT_PUBLIC_SUPABASE_ANON_KEY`, and, once the first GraphQL operation exists, `NEXT_PUBLIC_GRAPHQL_URL`. Missing configuration stops the relevant process with a named error; no template supplies credential defaults.
34
38
 
39
+ Production browser build values live in `.starcistacks/application-stacks.yaml` under `environments.production.deploy.images.web.buildArgs.values`. Before building deployment images, replace the placeholders with your site's public origin, your Supabase project's public URL, and its public anonymous key. These values reach every browser; keep the service role key in sealed runtime custody.
40
+
35
41
  `npm test` runs the back end's unit specs with per-file coverage. Optional integration specs run with `npm run test:integration` against the local Supabase stack (`npm run db:start`); a lite app has no e2e world.
36
42
 
37
43
  The public runtime template tracks only sealed member names. Scaffolding creates this app's own age recipient and encrypts generated placeholder values into the declared `.starcistacks/<environment>/secrets/*.enc` members. Keep the matching host age identity in untracked local custody, then use `starci app secret set` to replace each placeholder with an actual value before deployment. Product apps retain sealed member custody. Runtime specs use disposable copies with ephemeral identities and remove them afterwards.
@@ -1,4 +1,6 @@
1
1
  schema: starci/application-stacks@1
2
+ # To render README badges, declare ci.github: {repository: owner/repo, defaultBranch: main}.
3
+ # A GitHub package.json repository URL also enables the managed block.
2
4
  sources:
3
5
  - repository: "{{project}}"
4
6
  components:
@@ -28,11 +30,60 @@ environments:
28
30
  k8s:
29
31
  status: deferred
30
32
  reason: The upgrade establishes the full local stack first; deployment topology is selected separately.
33
+ ci:
34
+ secrets:
35
+ - {name: SONAR_TOKEN, scope: repository, purpose: Sonar analysis token provisioned for this app, optional: true}
36
+ - {name: SOPS_AGE_KEY, scope: repository, purpose: Decrypt app members during deployment, optional: true}
37
+ - {name: VPS_SSH_KEY, scope: repository, purpose: Deployment SSH key, optional: true}
38
+ - {name: VPS_KNOWN_HOSTS, scope: repository, purpose: Pinned deployment SSH host keys, optional: true}
39
+ vars:
40
+ - {name: SONAR_HOST_URL, scope: repository, value: "https://sonar.{{project}}.example.invalid", purpose: Documentation endpoint to replace with this app's public Sonar host, optional: true}
41
+ - {name: VPS_HOST, scope: repository, value: 203.0.113.10, purpose: Documentation deployment address to replace before use, optional: true}
42
+ - {name: VPS_USER, scope: repository, value: deploy, purpose: Documentation deployment user to replace before use, optional: true}
31
43
  services:
32
44
  sonar:
33
45
  provider: sonarqube
34
46
  mode: disabled
35
47
  reason: Enable the repository's Sonar service when a host and project token are provisioned.
36
48
  qualityGate: starci-quality
37
- ci: { wiring: not-used }
49
+ credentials: []
50
+ projects: [{repository: "{{project}}", key: "{{project}}"}]
51
+ ci: {wiring: optional-follow-up, workflow: .github/workflows/ci.yml, token: SONAR_TOKEN, hostVar: SONAR_HOST_URL}
52
+ ownerAction: none
53
+ codecov:
54
+ provider: codecov
55
+ mode: hosted
56
+ purpose: Report application coverage through GitHub OIDC.
57
+ auth: oidc
58
+ target: 100
59
+ components: auto
60
+ required: true
61
+ ci: {wiring: optional-follow-up, workflow: .github/workflows/ci.yml}
62
+ ownerAction: none
63
+ dependabot:
64
+ provider: github
65
+ mode: hosted
66
+ purpose: Keep application dependencies and workflow actions current.
67
+ ecosystems: [npm, docker, github-actions]
68
+ schedule: {interval: weekly}
69
+ groups: {minorPatch: grouped, major: per-package}
70
+ ignore: ['@starci/*']
71
+ security: immediate
72
+ ownerAction: none
73
+ audit:
74
+ provider: npm
75
+ mode: local
76
+ purpose: Refuse high severity production dependency vulnerabilities.
77
+ level: high
78
+ omitDev: true
79
+ in: [release-gate, ci]
80
+ ownerAction: none
81
+ container-registry:
82
+ provider: ghcr
83
+ mode: hosted
84
+ purpose: Publish this app's deployment images with the workflow GitHub token.
85
+ host: {public: https://ghcr.io}
86
+ auth: github-token
87
+ projects: [{repository: "{{project}}", key: "{{project}}"}]
88
+ ci: {wiring: optional-follow-up}
38
89
  ownerAction: none
package/upgrade/index.mjs CHANGED
@@ -413,7 +413,7 @@ async function model({ root, to, presets, manifest }) {
413
413
  * Plans or applies the lite -> full migration. Returns the ordered public plan (`{op,path,why}[]`) in both modes.
414
414
  * `presets` and `lock` are test seams for the full managed render and npm lock resolution.
415
415
  */
416
- export async function upgradeEdition({
416
+ async function upgradeEdition({
417
417
  root,
418
418
  to,
419
419
  plan = false,