@starci/hfs 4.12.0 → 4.13.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 (152) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +8 -9
  3. package/cache/app-families.d.mts +30 -0
  4. package/cache/app-families.mjs +94 -0
  5. package/cache/content-index.d.mts +13 -0
  6. package/cache/content-index.mjs +37 -0
  7. package/cache/db-family.d.mts +13 -0
  8. package/cache/db-family.mjs +37 -0
  9. package/cache/fake-session.d.mts +42 -0
  10. package/cache/fake-session.mjs +57 -0
  11. package/cache/fingerprint.d.mts +28 -0
  12. package/cache/fingerprint.mjs +120 -0
  13. package/cache/format-family.d.mts +13 -0
  14. package/cache/format-family.mjs +49 -0
  15. package/cache/git.d.mts +11 -0
  16. package/cache/git.mjs +13 -0
  17. package/cache/hash.d.mts +15 -0
  18. package/cache/hash.mjs +58 -0
  19. package/cache/hfs-family.d.mts +35 -0
  20. package/cache/hfs-family.mjs +164 -0
  21. package/cache/import-graph.d.mts +75 -0
  22. package/cache/import-graph.mjs +204 -0
  23. package/cache/jsonl.d.mts +31 -0
  24. package/cache/jsonl.mjs +115 -0
  25. package/cache/lint-family.d.mts +162 -0
  26. package/cache/lint-family.mjs +433 -0
  27. package/cache/order.d.mts +1 -0
  28. package/cache/order.mjs +2 -0
  29. package/cache/progress.d.mts +19 -0
  30. package/cache/progress.mjs +68 -0
  31. package/cache/quality-baselines.d.mts +109 -0
  32. package/cache/quality-baselines.mjs +235 -0
  33. package/cache/records.d.mts +33 -0
  34. package/cache/records.mjs +54 -0
  35. package/cache/report.d.mts +19 -0
  36. package/cache/report.mjs +32 -0
  37. package/cache/run-log.d.mts +17 -0
  38. package/cache/run-log.mjs +37 -0
  39. package/cache/run.d.mts +33 -0
  40. package/cache/run.mjs +65 -0
  41. package/cache/session.d.mts +29 -0
  42. package/cache/session.mjs +197 -0
  43. package/cache/side-key.d.mts +10 -0
  44. package/cache/side-key.mjs +47 -0
  45. package/cache/test-family.d.mts +130 -0
  46. package/cache/test-family.mjs +258 -0
  47. package/cache/trust.d.mts +53 -0
  48. package/cache/trust.mjs +157 -0
  49. package/cache/types-family.d.mts +74 -0
  50. package/cache/types-family.mjs +154 -0
  51. package/cache/types.d.mts +99 -0
  52. package/cache/types.mjs +8 -0
  53. package/cache/wiring-family.d.mts +14 -0
  54. package/cache/wiring-family.mjs +43 -0
  55. package/coverage/cli.d.mts +4 -2
  56. package/coverage/cli.mjs +44 -5
  57. package/db/migrate.d.mts +16 -0
  58. package/db/migrate.mjs +21 -4
  59. package/db/postgres.d.mts +23 -0
  60. package/db/postgres.mjs +32 -1
  61. package/lint/run.d.mts +47 -1
  62. package/lint/run.mjs +157 -5
  63. package/package.json +2 -1
  64. package/release/gate.d.mts +2 -0
  65. package/release/gate.mjs +4 -2
  66. package/release/records.d.mts +15 -0
  67. package/release/records.mjs +25 -0
  68. package/release/urgent.mjs +23 -4
  69. package/runtime/knowledge/grammars/core/playbook.yaml +12 -18
  70. package/runtime/knowledge/hfs/canon-pins.yaml +8 -8
  71. package/runtime/knowledge/hfs/ci-standard.yaml +29 -6
  72. package/runtime/knowledge/hfs/rules.yaml +97 -7
  73. package/runtime/knowledge/hfs/slots.yaml +19 -7
  74. package/runtime/modules/kernel/failure-codes.yaml +46 -4
  75. package/runtime/modules/schemas/application-stacks.schema.yaml +26 -0
  76. package/runtime/scripts/hfs/architecture/hfs.d.mts +6 -6
  77. package/runtime/scripts/hfs/check.mjs +1 -1
  78. package/runtime/scripts/hfs/gate-threshold.mjs +2 -1
  79. package/runtime/scripts/hfs/rules/boot-proof.d.mts +5 -0
  80. package/runtime/scripts/hfs/rules/boot-proof.mjs +15 -1
  81. package/runtime/scripts/hfs/rules/ci-custody.mjs +3 -1
  82. package/runtime/scripts/hfs/rules/ci-standard.mjs +32 -3
  83. package/runtime/scripts/hfs/rules/database-migrations.d.mts +14 -0
  84. package/runtime/scripts/hfs/rules/database-migrations.mjs +55 -0
  85. package/runtime/scripts/hfs/rules/database.mjs +2 -1
  86. package/runtime/scripts/hfs/rules/deploy-workflow.mjs +53 -6
  87. package/runtime/scripts/hfs/rules/release-provenance.mjs +32 -4
  88. package/runtime/scripts/hfs/rules/stacks.mjs +5 -1
  89. package/runtime/scripts/hfs/rules/supply-chain.mjs +4 -1
  90. package/runtime/scripts/hfs/rules/unused-symbol-translators.mjs +98 -7
  91. package/runtime/scripts/hfs/rules/unused-symbol.d.mts +9 -2
  92. package/runtime/scripts/hfs/rules/unused-symbol.mjs +15 -2
  93. package/runtime/scripts/hfs/runtime-rules/git-triggers.mjs +21 -5
  94. package/runtime/scripts/hfs/stack-deploy-config.d.mts +6 -0
  95. package/runtime/scripts/hfs/stack-deploy-config.mjs +32 -1
  96. package/runtime/scripts/hfs/stacks-gate.mjs +2 -0
  97. package/runtime/scripts/hfs/tree-findings.mjs +3 -1
  98. package/scaffold/add-inbox-lite.mjs +2 -4
  99. package/scaffold/add-queue-lite.mjs +2 -3
  100. package/scaffold/add-table.mjs +2 -4
  101. package/scaffold/migration-stamp.d.mts +11 -0
  102. package/scaffold/migration-stamp.mjs +32 -0
  103. package/src/helpers/hfs-arch-fixture.d.mts +1 -1
  104. package/src/main.d.mts +4 -1
  105. package/src/main.mjs +189 -74
  106. package/src/stack-records-double.d.mts +31 -0
  107. package/stack/cli.d.mts +3 -1
  108. package/stack/cli.mjs +17 -11
  109. package/stack/config.d.mts +6 -0
  110. package/stack/converge.d.mts +2 -0
  111. package/stack/converge.mjs +1 -1
  112. package/stack/db-phases.d.mts +185 -0
  113. package/stack/db-phases.mjs +346 -0
  114. package/stack/deploy.d.mts +18 -4
  115. package/stack/deploy.mjs +235 -70
  116. package/stack/journal.d.mts +127 -0
  117. package/stack/journal.mjs +182 -0
  118. package/stack/manager-backup.d.mts +54 -0
  119. package/stack/manager-backup.mjs +136 -0
  120. package/stack/release-store.d.mts +44 -0
  121. package/stack/release-store.mjs +89 -6
  122. package/stack/remote.d.mts +2 -0
  123. package/stack/remote.mjs +31 -11
  124. package/stack/server-key.d.mts +2 -0
  125. package/stack/server-key.mjs +1 -1
  126. package/stack/status.d.mts +49 -0
  127. package/stack/status.mjs +114 -0
  128. package/stack/urgent-floor.d.mts +10 -61
  129. package/stack/urgent-floor.mjs +28 -123
  130. package/stack/verify.mjs +26 -0
  131. package/sync/ci-commands.mjs +10 -5
  132. package/sync/format-worker.d.mts +1 -0
  133. package/sync/format-worker.mjs +17 -0
  134. package/sync/format.d.mts +21 -3
  135. package/sync/format.mjs +99 -7
  136. package/sync/index.d.mts +3 -6
  137. package/sync/index.mjs +12 -12
  138. package/sync/stack-images.d.mts +25 -10
  139. package/sync/stack-images.mjs +215 -54
  140. package/templates/app/ci-workflows/github/workflows/ci.yml +114 -7
  141. package/templates/app/ci-workflows/github/workflows/images.yml +21 -65
  142. package/templates/app/ci-workflows/github/workflows/stack-deploy.yml +130 -37
  143. package/templates/app/ci-workflows-lite/github/workflows/ci.yml +114 -7
  144. package/templates/app/ci-workflows-lite/github/workflows/images.yml +21 -65
  145. package/templates/app/ci-workflows-lite/github/workflows/stack-deploy.yml +130 -37
  146. package/templates/app/gitignore +1 -0
  147. package/templates/app/gitignore-lite +1 -0
  148. package/templates/app/package-scripts/db.json +1 -1
  149. package/templates/app/skeleton/.gitattributes +2 -0
  150. package/templates/app/skeleton-lite/.gitattributes +2 -0
  151. package/templates/be/skeleton/src/modules/platform/config/env-source.config.ts +2 -1
  152. package/templates/app/ci-workflows-lite/github/workflows/db-deploy.yml +0 -63
@@ -1,33 +1,70 @@
1
1
  {{header}}
2
- # Deploys the app's Docker Swarm stack. This file only assembles arguments: the logic lives in the verbs connect, build-args, deploy,
3
- # rollback and disconnect of "starci app stack". It runs by hand only (Actions > deploy stack > Run workflow) from a release tag v*
4
- # whose version is the package.json version; it has no push or schedule trigger.
5
- # operation deploy builds and pushes one image per environments.<env>.deploy.images entry of .starcistacks/application-stacks.yaml,
6
- # then deploys their immutable digests (render, provision, converge, post-deploy tasks, verify, accept; a failure redeploys the previous release)
2
+ # Deploys the app's Docker Swarm stack. This file only assembles arguments: the logic lives in the verbs connect, deploy, rollback and disconnect
3
+ # of "starci app stack". It has two callers:
4
+ # ci.yml calls it (workflow_call) once per environment with deploy.auto, after the verdict job, with the digests of the images that run
5
+ # pushed and the CI run that proves the commit. A green release tag deploys by itself.
6
+ # by hand Actions > deploy stack > Run workflow, from a release tag v* whose version is the package.json version.
7
+ # operation deploy deploys the release of the tag: the immutable digests of its images (the run's, or the registry's sha-<sha> tags when
8
+ # dispatched), the CI evidence of the commit, then render, store, pre-pull, migrate (expand), converge, post-deploy, verify, accept
9
+ # and the contract migrations; a failure redeploys the previous accepted release
10
+ # operation redeploy the same, although the accepted release already runs this commit
7
11
  # operation rollback redeploys a stored release; "release" is 16 lowercase hex characters, empty means the previous accepted release
8
- # The environment input names a protected GitHub environment (required reviewers) that holds:
9
- # vars VPS_HOST, VPS_USER (the swarm manager); a variable named in deploy.passEnv, when the stack interpolates one
12
+ # The environment names a GitHub environment whose deployment refs are restricted to the tags v* and that holds:
13
+ # vars STARCI_DEPLOY_PAUSED (true stops the automatic deploy of that environment without a code change; a manual run still works), and a
14
+ # variable named in deploy.passEnv when the stack interpolates one
10
15
  # secrets SOPS_AGE_KEY (that environment's server identity, stored there by starci app secret server-key --env <env> --backup github --execute;
11
- # both jobs are bound to the environment, so they read it and never a repository secret of that name), VPS_SSH_KEY
12
- # (CI-only deploy key), VPS_KNOWN_HOSTS (pinned host keys)
13
- # Nothing else is a secret: images are pushed with the workflow token, which also reads the CI verdict of the tag's commit a production deploy
14
- # waits for (requireCi deploy.prod). Dispatch inputs reach scripts only through env.
16
+ # the jobs are bound to the environment, so they read it and never a repository secret of that name)
17
+ # The transport is sealed: the CI deploy key, the pinned host keys and the host are the member vps-ci under .starcistacks/<env>/secrets, opened with
18
+ # the server identity (a key of its own, never the owner's, authorised on the manager with a forced command). Nothing else is a secret: the images
19
+ # are read with the workflow token. Inputs reach scripts only through env. The log of a public repository is public: no step prints a host or a path.
15
20
  name: deploy stack
16
21
 
17
22
  on:
23
+ workflow_call:
24
+ inputs:
25
+ environment:
26
+ description: GitHub environment holding the server identity and the sealed custody under .starcistacks
27
+ required: true
28
+ type: string
29
+ operation:
30
+ description: deploy, redeploy or rollback
31
+ required: false
32
+ type: string
33
+ default: deploy
34
+ release:
35
+ description: "Rollback only: release id (16 lowercase hex) to deploy again; empty means the previous accepted release"
36
+ required: false
37
+ type: string
38
+ default: ""
39
+ images:
40
+ description: "JSON object, service -> repository@sha256:digest of the images the calling run pushed; empty reads the registry's sha-<sha> tags"
41
+ required: false
42
+ type: string
43
+ default: ""
44
+ ci_run:
45
+ description: Id of the CI run that proves the commit; empty finds the green CI run of the commit
46
+ required: false
47
+ type: string
48
+ default: ""
49
+ auto:
50
+ description: The automatic deploy of a green release tag (it stops when STARCI_DEPLOY_PAUSED is true)
51
+ required: false
52
+ type: boolean
53
+ default: false
18
54
  workflow_dispatch:
19
55
  inputs:
20
56
  environment:
21
- description: Protected environment holding the VPS variables and the sealed custody under .starcistacks
57
+ description: GitHub environment holding the server identity and the sealed custody under .starcistacks
22
58
  required: true
23
59
  type: environment
24
60
  operation:
25
- description: Deploy a new release or roll back to a stored one
61
+ description: Deploy the release of this tag, deploy it again, or roll back to a stored release
26
62
  required: true
27
63
  type: choice
28
64
  default: deploy
29
65
  options:
30
66
  - deploy
67
+ - redeploy
31
68
  - rollback
32
69
  release:
33
70
  description: "Rollback only: release id (16 lowercase hex) to deploy again; empty means the previous accepted release"
@@ -38,69 +75,125 @@ on:
38
75
  permissions:
39
76
  contents: read
40
77
 
41
- concurrency:
42
- group: stack-${{ inputs.environment }}
43
- cancel-in-progress: false
44
-
45
78
  jobs:
46
- release:
47
- if: ${{ inputs.operation == 'deploy' }}
79
+ deploy:
80
+ if: ${{ inputs.operation != 'rollback' }}
48
81
  runs-on: ubuntu-latest
49
82
  environment: ${{ inputs.environment }}
50
83
  timeout-minutes: 60
51
84
  permissions:
52
85
  contents: read
53
- packages: write
86
+ packages: read
54
87
  actions: read
88
+ concurrency:
89
+ group: stack-${{ inputs.environment }}
90
+ cancel-in-progress: false
55
91
  env:
56
92
  STACK_ENVIRONMENT: ${{ inputs.environment }}
57
93
  steps:{{stackGuard}}
58
94
  - name: require release tag
59
95
  shell: bash
60
96
  run: '[[ "$GITHUB_REF" == refs/tags/v* ]] || exit 1'
97
+ - name: deploy pause
98
+ id: pause
99
+ shell: bash
100
+ env:
101
+ AUTO: ${{ inputs.auto }}
102
+ PAUSED: ${{ vars.STARCI_DEPLOY_PAUSED }}
103
+ run: |
104
+ if [[ "$AUTO" == true && "$PAUSED" == true ]]; then
105
+ echo "paused=true" >> "$GITHUB_OUTPUT"
106
+ echo "::notice::STARCI_DEPLOY_PAUSED is true for this environment: this release was not deployed"
107
+ echo "### Deploy paused" >> "$GITHUB_STEP_SUMMARY"
108
+ echo "STARCI_DEPLOY_PAUSED is true for this environment, so the automatic deploy was skipped. Run this workflow by hand to deploy the release." >> "$GITHUB_STEP_SUMMARY"
109
+ else
110
+ echo "paused=false" >> "$GITHUB_OUTPUT"
111
+ fi
61
112
  - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
113
+ if: ${{ steps.pause.outputs.paused != 'true' }}
62
114
  - name: release tag matches package version
115
+ if: ${{ steps.pause.outputs.paused != 'true' }}
63
116
  run: node -e "const version=require('./package.json').version;if(process.env.GITHUB_REF_NAME!=='v'+version)process.exit(1)"
64
117
  - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
118
+ if: ${{ steps.pause.outputs.paused != 'true' }}
65
119
  with:
66
120
  node-version: {{nodeMajor}}
67
121
  cache: npm
68
122
  - run: npm ci --ignore-scripts
123
+ if: ${{ steps.pause.outputs.paused != 'true' }}
69
124
  - name: install SOPS
125
+ if: ${{ steps.pause.outputs.paused != 'true' }}
70
126
  uses: mdgreenwald/mozilla-sops-action@bb2d96a13ef438ad122e5827a57ebd75d6ff118d # v2.1.0
71
127
  with:
72
128
  version: v3.13.2
73
- - name: image repositories
74
- id: names
75
- shell: bash
76
- run: |
77
- owner="${GITHUB_REPOSITORY_OWNER,,}"{{stackNames}}
78
129
  - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
130
+ if: ${{ steps.pause.outputs.paused != 'true' }}
79
131
  - uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
132
+ if: ${{ steps.pause.outputs.paused != 'true' }}
80
133
  with:
81
134
  registry: ghcr.io
82
135
  username: ${{ github.actor }}
83
- password: ${{ github.token }}{{stackImageSteps}}
136
+ password: ${{ github.token }}
137
+ - name: image digests
138
+ id: images
139
+ if: ${{ steps.pause.outputs.paused != 'true' }}
140
+ shell: bash
141
+ env:
142
+ IMAGES: ${{ inputs.images }}
143
+ run: |
144
+ set -euo pipefail
145
+ owner="${GITHUB_REPOSITORY_OWNER,,}"
146
+ [[ -n "$IMAGES" ]] || IMAGES='{}'
147
+ while read -r service app; do
148
+ ref=$(jq -r --arg service "$service" '.[$service] // empty' <<<"$IMAGES")
149
+ if [[ -z "$ref" ]]; then
150
+ repo="ghcr.io/${owner}/{{project}}-${app}"
151
+ digest=$(docker buildx imagetools inspect "$repo:sha-$GITHUB_SHA" --format '{{json .Manifest}}' | jq -r .digest)
152
+ ref="${repo}@${digest}"
153
+ fi
154
+ [[ "$ref" =~ ^ghcr\.io/[a-z0-9._/-]+@sha256:[0-9a-f]{64}$ ]] || { echo "::error::no immutable image for ${service}"; exit 1; }
155
+ echo "${service}=${ref}" >> "$GITHUB_OUTPUT"
156
+ done <<'LIST'
157
+ {{stackImageList}}
158
+ LIST
159
+ - name: CI run of the commit
160
+ id: ci
161
+ if: ${{ steps.pause.outputs.paused != 'true' }}
162
+ shell: bash
163
+ env:
164
+ GH_TOKEN: ${{ github.token }}
165
+ CI_RUN: ${{ inputs.ci_run }}
166
+ run: |
167
+ set -euo pipefail
168
+ if [[ -z "$CI_RUN" ]]; then
169
+ CI_RUN=$(gh api "repos/${GITHUB_REPOSITORY}/actions/workflows/ci.yml/runs?head_sha=${GITHUB_SHA}&event=push&status=success&per_page=100" --jq '[.workflow_runs[].id] | first // empty')
170
+ fi
171
+ [[ "$CI_RUN" =~ ^[1-9][0-9]*$ ]] || { echo "::error::no green CI run of this commit: a release deploys only a commit the CI proved"; exit 1; }
172
+ echo "run=$CI_RUN" >> "$GITHUB_OUTPUT"
84
173
  - name: connect to the swarm manager
174
+ if: ${{ steps.pause.outputs.paused != 'true' }}
85
175
  env:
86
176
  XDG_DATA_HOME: ${{ runner.temp }}/starci-data
87
- VPS_SSH_KEY: ${{ secrets.VPS_SSH_KEY }}
88
- VPS_KNOWN_HOSTS: ${{ secrets.VPS_KNOWN_HOSTS }}
89
- VPS_HOST: ${{ vars.VPS_HOST }}
90
- VPS_USER: ${{ vars.VPS_USER }}
177
+ SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY }}
91
178
  run: npx --no-install starci app stack connect --env "$STACK_ENVIRONMENT" --execute
92
179
  - name: deploy the release
180
+ if: ${{ steps.pause.outputs.paused != 'true' }}
181
+ shell: bash
93
182
  env:
94
183
  XDG_DATA_HOME: ${{ runner.temp }}/starci-data
95
184
  GH_TOKEN: ${{ github.token }}
96
- SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY }}{{stackImageEnv}}{{stackPassEnv}}
185
+ SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY }}
186
+ OPERATION: ${{ inputs.operation }}
187
+ CI_RUN: ${{ steps.ci.outputs.run }}{{stackImageEnv}}{{stackPassEnv}}
97
188
  run: |
189
+ again=()
190
+ [[ "$OPERATION" != redeploy ]] || again=(--redeploy)
98
191
  npx --no-install starci app stack deploy --env "$STACK_ENVIRONMENT" \{{stackImageArgs}}
99
- --sha "$GITHUB_SHA" --execute
192
+ --sha "$GITHUB_SHA" --ci-run "$CI_RUN" "${again[@]}" --execute
100
193
  - name: disconnect from the swarm manager
101
194
  env:
102
195
  XDG_DATA_HOME: ${{ runner.temp }}/starci-data
103
- if: ${{ always() }}
196
+ if: ${{ always() && steps.pause.outputs.paused != 'true' }}
104
197
  run: npx --no-install starci app stack disconnect --env "$STACK_ENVIRONMENT" --execute
105
198
 
106
199
  rollback:
@@ -111,6 +204,9 @@ jobs:
111
204
  permissions:
112
205
  contents: read
113
206
  packages: read
207
+ concurrency:
208
+ group: stack-${{ inputs.environment }}
209
+ cancel-in-progress: false
114
210
  env:
115
211
  STACK_ENVIRONMENT: ${{ inputs.environment }}
116
212
  steps:
@@ -137,10 +233,7 @@ jobs:
137
233
  - name: connect to the swarm manager
138
234
  env:
139
235
  XDG_DATA_HOME: ${{ runner.temp }}/starci-data
140
- VPS_SSH_KEY: ${{ secrets.VPS_SSH_KEY }}
141
- VPS_KNOWN_HOSTS: ${{ secrets.VPS_KNOWN_HOSTS }}
142
- VPS_HOST: ${{ vars.VPS_HOST }}
143
- VPS_USER: ${{ vars.VPS_USER }}
236
+ SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY }}
144
237
  run: npx --no-install starci app stack connect --env "$STACK_ENVIRONMENT" --execute
145
238
  - name: redeploy the stored release
146
239
  env:
@@ -13,6 +13,7 @@ next-env.d.ts
13
13
  !.starcistacks/**/KEYS.md
14
14
  !.starcistacks/**/.gitkeep
15
15
  !.starcistacks/application-stacks.yaml
16
+ !.starcistacks/cache/**
16
17
  !.starcistacks/*/README.md
17
18
  !.starcistacks/*/environment.json
18
19
  !.starcistacks/*/seeds/**
@@ -13,6 +13,7 @@ next-env.d.ts
13
13
  !.starcistacks/**/KEYS.md
14
14
  !.starcistacks/**/.gitkeep
15
15
  !.starcistacks/application-stacks.yaml
16
+ !.starcistacks/cache/**
16
17
  !.starcistacks/images/db/Dockerfile
17
18
  !.starcistacks/*/README.md
18
19
  !.starcistacks/*/environment.json
@@ -7,4 +7,4 @@
7
7
  "db:push": "{{appBinary}} db migrate --db-url-env DATABASE_URL --execute",
8
8
  "db:plan": "{{appBinary}} db migrate --db-url-env DATABASE_URL",
9
9
  "db:dump": "{{appBinary}} db dump --db-url-env DATABASE_URL --out ../{{project}}-db-backups",
10
- "db:lint": "{{appBinary}} check --fast",
10
+ "db:lint": "{{appBinary}} check --db",
@@ -6,3 +6,5 @@
6
6
  *.mjs text eol=lf
7
7
  .starcistacks/** text eol=lf
8
8
  .starcistacks/**/*.enc binary
9
+ # The committed check cache (starci app check): union-merged JSON Lines, never a conflict; hidden from language statistics and review diffs.
10
+ .starcistacks/cache/** text eol=lf merge=union linguist-generated=true
@@ -6,3 +6,5 @@
6
6
  *.mjs text eol=lf
7
7
  .starcistacks/** text eol=lf
8
8
  .starcistacks/**/*.enc binary
9
+ # The committed check cache (starci app check): union-merged JSON Lines, never a conflict; hidden from language statistics and review diffs.
10
+ .starcistacks/cache/** text eol=lf merge=union linguist-generated=true
@@ -60,7 +60,8 @@ export class EnvSource {
60
60
  optionalDomain(key: string): string | undefined {
61
61
  const value = this.optional(key)?.toLowerCase()
62
62
  if (value === undefined) return undefined
63
- if (!BARE_DOMAIN_PATTERN.test(value)) throw new ConfigError({ code: ConfigErrorCode.KeyInvalid, params: { key } })
63
+ if (!BARE_DOMAIN_PATTERN.test(value))
64
+ throw new ConfigError({ code: ConfigErrorCode.KeyInvalid, params: { key } })
64
65
  return value
65
66
  }
66
67
 
@@ -1,63 +0,0 @@
1
- {{header}}
2
- name: deploy database
3
-
4
- on:
5
- workflow_dispatch:
6
- inputs:
7
- environment:
8
- description: Protected environment whose sealed custody under .starcistacks holds DATABASE_URL
9
- required: true
10
- type: environment
11
- backup_receipt:
12
- description: Tracked backup receipt path verified by the deployment owner before migration
13
- required: true
14
- type: string
15
-
16
- permissions:
17
- contents: read
18
-
19
- concurrency:
20
- group: database-${{ inputs.environment }}
21
- cancel-in-progress: false
22
-
23
- jobs:
24
- deploy:
25
- timeout-minutes: 30
26
- runs-on: ubuntu-latest
27
- environment: ${{ inputs.environment }}
28
- env:
29
- STACK_ENVIRONMENT: ${{ inputs.environment }}
30
- BACKUP_RECEIPT: ${{ inputs.backup_receipt }}
31
- SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY }}
32
- steps:
33
- - name: require release tag
34
- shell: bash
35
- run: '[[ "$GITHUB_REF" == refs/tags/v* ]] || exit 1'
36
- - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
37
- - name: release tag matches package version
38
- run: node -e "const version=require('./package.json').version;if(process.env.GITHUB_REF_NAME!=='v'+version)process.exit(1)"
39
- - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
40
- with:
41
- node-version: {{nodeMajor}}
42
- cache: npm
43
- - run: npm ci --ignore-scripts
44
- - name: install SOPS
45
- uses: mdgreenwald/mozilla-sops-action@bb2d96a13ef438ad122e5827a57ebd75d6ff118d # v2.1.0
46
- with:
47
- version: v3.13.2
48
- - name: materialize sealed custody and migrate the database
49
- env:
50
- XDG_DATA_HOME: ${{ runner.temp }}/starci-data
51
- shell: bash
52
- run: |
53
- set -euo pipefail
54
- [[ "$STACK_ENVIRONMENT" =~ ^[a-z][a-z0-9-]*$ ]]
55
- git ls-files --error-unmatch -- "$BACKUP_RECEIPT" > /dev/null
56
- test -s "$BACKUP_RECEIPT"
57
- secret_dir="$XDG_DATA_HOME/StarCi/secrets/{{project}}/$STACK_ENVIRONMENT"
58
- trap 'rm -rf -- "$secret_dir"' EXIT
59
- npx --no-install starci app secret materialize --env "$STACK_ENVIRONMENT"
60
- DATABASE_URL="$(cat "$secret_dir/DATABASE_URL")"
61
- export DATABASE_URL
62
- npx --no-install starci app db migrate --db-url-env DATABASE_URL || test "$?" -eq 1
63
- STARCI_DB_ARMED=1 npx --no-install starci app db migrate --db-url-env DATABASE_URL --execute