@starci/hfs 4.4.1 → 4.5.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.
Files changed (66) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/ci/cli.mjs +64 -0
  3. package/ci/github.mjs +41 -0
  4. package/ci/secret.mjs +28 -0
  5. package/ci/vars.mjs +33 -0
  6. package/ci/verify.mjs +36 -0
  7. package/db/backup-receipt.mjs +129 -0
  8. package/db/dump.mjs +66 -0
  9. package/db/migrate.mjs +4 -1
  10. package/db/reset.mjs +125 -0
  11. package/emit/db-types.mjs +98 -5
  12. package/lint/run.mjs +28 -6
  13. package/package.json +2 -1
  14. package/release/ci-red.mjs +70 -0
  15. package/release/gate.mjs +98 -27
  16. package/release/index.mjs +6 -4
  17. package/release/push.mjs +1 -1
  18. package/runtime/knowledge/hfs/canon-pins.yaml +5 -5
  19. package/runtime/knowledge/hfs/rules.yaml +95 -4
  20. package/runtime/modules/kernel/failure-codes.yaml +60 -0
  21. package/runtime/modules/schemas/application-stacks.schema.yaml +134 -1
  22. package/runtime/packages/cli/src/catalog.generated.mjs +243 -20
  23. package/runtime/scripts/hfs/ci-declaration.mjs +102 -0
  24. package/runtime/scripts/hfs/rules/a15-findings.mjs +9 -0
  25. package/runtime/scripts/hfs/rules/app-workflow-findings.mjs +10 -0
  26. package/runtime/scripts/hfs/rules/ci-custody.mjs +104 -0
  27. package/runtime/scripts/hfs/rules/deploy-workflow.mjs +6 -19
  28. package/runtime/scripts/hfs/rules/fe-build-args.mjs +142 -0
  29. package/runtime/scripts/hfs/rules/supply-chain.mjs +40 -3
  30. package/runtime/scripts/hfs/rules/workflow-contexts.mjs +103 -0
  31. package/runtime/scripts/lib/secret-patterns.mjs +2 -2
  32. package/src/main.mjs +17 -6
  33. package/stack/context.mjs +13 -1
  34. package/stack/docker-transport.mjs +93 -15
  35. package/stack/release-store.mjs +12 -7
  36. package/stack/remote.mjs +14 -6
  37. package/stack/ssh-session.mjs +178 -0
  38. package/sync/ci-commands.mjs +205 -1
  39. package/sync/index.mjs +42 -16
  40. package/sync/quality-services.mjs +61 -0
  41. package/sync/readme-badges.mjs +44 -0
  42. package/sync/stack-images.mjs +29 -3
  43. package/templates/app/ci-workflows/github/workflows/ci.yml +33 -25
  44. package/templates/app/ci-workflows/github/workflows/e2e.yml +1 -0
  45. package/templates/app/ci-workflows/github/workflows/images.yml +25 -2
  46. package/templates/app/ci-workflows/github/workflows/stack-deploy.yml +8 -2
  47. package/templates/app/ci-workflows/install-steps.yml +23 -0
  48. package/templates/app/ci-workflows/jest-cache.yml +8 -0
  49. package/templates/app/ci-workflows/lint-base.yml +16 -0
  50. package/templates/app/ci-workflows/sonar-steps.yml +3 -9
  51. package/templates/app/ci-workflows-lite/github/workflows/ci.yml +36 -36
  52. package/templates/app/ci-workflows-lite/github/workflows/db-deploy.yml +3 -1
  53. package/templates/app/ci-workflows-lite/github/workflows/images.yml +25 -2
  54. package/templates/app/ci-workflows-lite/github/workflows/stack-deploy.yml +8 -2
  55. package/templates/app/gitignore +2 -0
  56. package/templates/app/gitignore-lite +2 -0
  57. package/templates/app/quality-config/codecov.yml +6 -6
  58. package/templates/app/quality-config/sonar-project.properties +1 -0
  59. package/templates/app/readme-badges/README.md +1 -0
  60. package/templates/app/skeleton/.github/dependabot.yml +1 -14
  61. package/templates/app/skeleton/.starcistacks/application-stacks.yaml +62 -3
  62. package/templates/app/skeleton/README.md +6 -0
  63. package/templates/app/skeleton-lite/.github/dependabot.yml +1 -14
  64. package/templates/app/skeleton-lite/.starcistacks/application-stacks.yaml +58 -3
  65. package/templates/app/skeleton-lite/README.md +6 -0
  66. package/templates/app/upgrade-full/.starcistacks/application-stacks.yaml +53 -1
@@ -17,21 +17,44 @@ concurrency:
17
17
 
18
18
  jobs:
19
19
  image:
20
- runs-on: ubuntu-latest
20
+ timeout-minutes: 30
21
+ runs-on: ubuntu-latest{{imageJobEnvironment}}
22
+ env:
23
+ STACK_ENVIRONMENT: {{imageEnvironment}}
21
24
  strategy:
22
25
  fail-fast: false
23
26
  matrix:
24
27
  include:
25
28
  {{imageMatrix}}
26
- steps:
29
+ steps:{{imageEnvironmentGuard}}
27
30
  - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
28
31
  - name: release tag matches package version
29
32
  run: node -e "const version=require('./package.json').version;if(process.env.GITHUB_REF_NAME!=='v'+version)process.exit(1)"
33
+ - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
34
+ if: {{imageBuildArgsIf}}
35
+ with:
36
+ node-version: {{nodeMajor}}
37
+ cache: npm
38
+ - run: npm ci --ignore-scripts
39
+ if: {{imageBuildArgsIf}}
40
+ - name: install SOPS
41
+ if: {{imageBuildArgsIf}}
42
+ uses: mdgreenwald/mozilla-sops-action@bb2d96a13ef438ad122e5827a57ebd75d6ff118d # v2.1.0
43
+ with:
44
+ version: v3.13.2
45
+ - name: public build values
46
+ id: args
47
+ if: {{imageBuildArgsIf}}
48
+ env:
49
+ SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY }}
50
+ IMAGE_APP: ${{ matrix.name }}
51
+ run: npx --no-install starci app stack build-args --env "$STACK_ENVIRONMENT" --app "$IMAGE_APP"
30
52
  - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
31
53
  - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
32
54
  with:
33
55
  context: .
34
56
  file: ${{ matrix.file }}
57
+ build-args: ${{ steps.args.outputs.args }}
35
58
  push: false
36
59
  tags: {{imageProject}}/${{ matrix.name }}:${{ github.ref_name }}
37
60
  # 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
@@ -0,0 +1,23 @@
1
+ - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
2
+ with:
3
+ fetch-depth: 0
4
+ - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
5
+ with:
6
+ node-version: {{nodeMajor}}
7
+ cache: npm
8
+ - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
9
+ id: deps
10
+ with:
11
+ path: node_modules
12
+ key: ${{ runner.os }}-node{{nodeMajor}}-modules-${{ hashFiles('package-lock.json') }}
13
+ - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
14
+ with:
15
+ path: |
16
+ .turbo
17
+ fe/apps/*/.next/cache
18
+ key: ${{ runner.os }}-node{{nodeMajor}}-build-${{ hashFiles('package-lock.json') }}-${{ github.sha }}
19
+ restore-keys: |
20
+ ${{ runner.os }}-node{{nodeMajor}}-build-${{ hashFiles('package-lock.json') }}-
21
+ ${{ runner.os }}-node{{nodeMajor}}-build-
22
+ - run: npm ci --ignore-scripts
23
+ if: steps.deps.outputs.cache-hit != 'true'
@@ -0,0 +1,8 @@
1
+ - name: Jest cache
2
+ uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
3
+ with:
4
+ path: .jest-cache
5
+ key: ${{ runner.os }}-node{{nodeMajor}}-jest-${{ hashFiles('package-lock.json') }}-${{ github.sha }}
6
+ restore-keys: |
7
+ ${{ runner.os }}-node{{nodeMajor}}-jest-${{ hashFiles('package-lock.json') }}-
8
+ ${{ runner.os }}-node{{nodeMajor}}-jest-
@@ -0,0 +1,16 @@
1
+ - name: lint baseline
2
+ shell: bash
3
+ env:
4
+ BASE_BRANCH: ${{ github.base_ref }}
5
+ DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
6
+ BEFORE: ${{ github.event.before }}
7
+ run: |
8
+ base="origin/$DEFAULT_BRANCH"
9
+ if [[ "$GITHUB_EVENT_NAME" == pull_request ]]; then
10
+ base="origin/$BASE_BRANCH"
11
+ elif [[ "$GITHUB_REF" == refs/tags/* ]]; then
12
+ base=$(git describe --tags --abbrev=0 "$GITHUB_REF^" 2>/dev/null) || base="origin/$DEFAULT_BRANCH"
13
+ elif [[ "$GITHUB_EVENT_NAME" == push && -n "$BEFORE" && ! "$BEFORE" =~ ^0+$ ]]; then
14
+ base="$BEFORE"
15
+ fi
16
+ echo "STARCI_BASE_REF=$base" >> "$GITHUB_ENV"
@@ -1,9 +1,3 @@
1
- - uses: SonarSource/sonarqube-scan-action@c7ee0f9df90b7aa20e8dcf9695dcfe2e7da5b4f2 # v7.2.1
2
- if: ${{ !cancelled() && startsWith(github.ref, 'refs/tags/v') && env.SONAR_TOKEN != '' }}
3
- env:
4
- SONAR_HOST_URL: ${{ vars.SONAR_HOST_URL }}
5
- - uses: SonarSource/sonarqube-quality-gate-action@7a5fffe8e523c40e0c740b6bc2712ab503e52efa # v1.2.1
6
- if: ${{ !cancelled() && startsWith(github.ref, 'refs/tags/v') && env.SONAR_TOKEN != '' }}
7
- timeout-minutes: 10
8
- env:
9
- SONAR_HOST_URL: ${{ vars.SONAR_HOST_URL }}
1
+ {{sonarJobHeader}}
2
+ {{> app/ci-workflows/install-steps.yml}}
3
+ {{sonarJobSteps}}
@@ -9,68 +9,68 @@ 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
+ timeout-minutes: 20
19
20
  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 }}
21
+ {{sonarEnv}}
26
22
  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
23
+ {{> app/ci-workflows/install-steps.yml}}
24
+ {{> app/ci-workflows/lint-base.yml}}
33
25
  - 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}}
26
+ run: {{auditCommand}}
27
+ {{ciLintSteps}}
41
28
  - name: format
42
29
  run: npm run format:check
43
30
  - name: typecheck
44
31
  run: npm run typecheck
32
+
33
+ test:
34
+ timeout-minutes: 45
35
+ runs-on: ubuntu-latest
36
+ # Codecov OIDC authentication requires a job-scoped identity token.
37
+ permissions:
38
+ contents: read
39
+ id-token: write
40
+ steps:
41
+ {{> app/ci-workflows/install-steps.yml}}
42
+ {{> app/ci-workflows/jest-cache.yml}}
45
43
  - name: unit
46
- run: npm test -- --ci
44
+ run: npm test -- --ci --forceExit --cacheDirectory .jest-cache
47
45
  - name: coverage proof
48
46
  run: {{ciCoverageProof}}
49
- - name: coverage upload
50
- uses: codecov/codecov-action@0fb7174895f61a3b6b78fc075e0cd60383518dac # v5.5.5
51
- if: ${{ !cancelled() && startsWith(github.ref, 'refs/tags/v') }}
47
+ - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
48
+ if: always() && hashFiles('{{lcovReport}}') != ''
52
49
  with:
53
- use_oidc: true
54
- files: {{lcovReport}}
55
- disable_search: true
56
- fail_ci_if_error: true
50
+ name: {{lcovArtifact}}
51
+ path: {{lcovReport}}
52
+ {{codecovSteps}}
53
+
54
+ build:
55
+ timeout-minutes: 30
56
+ runs-on: ubuntu-latest
57
+ steps:
58
+ {{> app/ci-workflows/install-steps.yml}}
57
59
  - name: build be
58
60
  run: npm run build:be
59
61
  - name: build fe
60
62
  run: npm run build:fe
63
+ {{ciBuildEnv}}
61
64
  - name: database migration checks
62
65
  run: {{ciDatabaseLint}}
63
- {{> app/ci-workflows/sonar-steps.yml}}
66
+
67
+ {{sonarJob}}
64
68
 
65
69
  db-types:
70
+ timeout-minutes: 30
66
71
  runs-on: ubuntu-latest
67
72
  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
73
+ {{> app/ci-workflows/install-steps.yml}}
74
74
  - name: start Supabase
75
75
  run: npm run db:start
76
76
  - name: apply migrations
@@ -22,13 +22,13 @@ concurrency:
22
22
 
23
23
  jobs:
24
24
  deploy:
25
+ timeout-minutes: 30
25
26
  runs-on: ubuntu-latest
26
27
  environment: ${{ inputs.environment }}
27
28
  env:
28
29
  STACK_ENVIRONMENT: ${{ inputs.environment }}
29
30
  BACKUP_RECEIPT: ${{ inputs.backup_receipt }}
30
31
  SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY }}
31
- XDG_DATA_HOME: ${{ runner.temp }}/starci-data
32
32
  steps:
33
33
  - name: require release tag
34
34
  shell: bash
@@ -46,6 +46,8 @@ jobs:
46
46
  with:
47
47
  version: v3.13.2
48
48
  - name: materialize sealed custody and push migrations
49
+ env:
50
+ XDG_DATA_HOME: ${{ runner.temp }}/starci-data
49
51
  shell: bash
50
52
  run: |
51
53
  set -euo pipefail
@@ -17,21 +17,44 @@ concurrency:
17
17
 
18
18
  jobs:
19
19
  image:
20
- runs-on: ubuntu-latest
20
+ timeout-minutes: 30
21
+ runs-on: ubuntu-latest{{imageJobEnvironment}}
22
+ env:
23
+ STACK_ENVIRONMENT: {{imageEnvironment}}
21
24
  strategy:
22
25
  fail-fast: false
23
26
  matrix:
24
27
  include:
25
28
  {{imageMatrix}}
26
- steps:
29
+ steps:{{imageEnvironmentGuard}}
27
30
  - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
28
31
  - name: release tag matches package version
29
32
  run: node -e "const version=require('./package.json').version;if(process.env.GITHUB_REF_NAME!=='v'+version)process.exit(1)"
33
+ - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
34
+ if: {{imageBuildArgsIf}}
35
+ with:
36
+ node-version: {{nodeMajor}}
37
+ cache: npm
38
+ - run: npm ci --ignore-scripts
39
+ if: {{imageBuildArgsIf}}
40
+ - name: install SOPS
41
+ if: {{imageBuildArgsIf}}
42
+ uses: mdgreenwald/mozilla-sops-action@bb2d96a13ef438ad122e5827a57ebd75d6ff118d # v2.1.0
43
+ with:
44
+ version: v3.13.2
45
+ - name: public build values
46
+ id: args
47
+ if: {{imageBuildArgsIf}}
48
+ env:
49
+ SOPS_AGE_KEY: ${{ secrets.SOPS_AGE_KEY }}
50
+ IMAGE_APP: ${{ matrix.name }}
51
+ run: npx --no-install starci app stack build-args --env "$STACK_ENVIRONMENT" --app "$IMAGE_APP"
30
52
  - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
31
53
  - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2
32
54
  with:
33
55
  context: .
34
56
  file: ${{ matrix.file }}
57
+ build-args: ${{ steps.args.outputs.args }}
35
58
  push: false
36
59
  tags: {{imageProject}}/${{ matrix.name }}:${{ github.ref_name }}
37
60
  # 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,4 +1,6 @@
1
1
  {{> common/gitignore.base}}
2
+ # Jest transforms reused by the CI test job
3
+ .jest-cache/
2
4
  # be: the schema Nest writes when it boots GraphQL
3
5
  schema.gql
4
6
  # fe: Next build output and its generated type file
@@ -1,4 +1,6 @@
1
1
  {{> common/gitignore.base}}
2
+ # Jest transforms reused by the CI test job
3
+ .jest-cache/
2
4
  # Supabase CLI state is local Docker metadata, never application source.
3
5
  supabase/.temp/
4
6
  supabase/.branches/
@@ -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,69 @@ 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
151
+ optional: true
132
152
  mode: local
133
153
  qualityGate: {{sonarGate}}
134
- host: { local: http://127.0.0.1:9000 }
154
+ host: {local: http://127.0.0.1:9000, public: "https://sonar.{{project}}.example.invalid"}
135
155
  stack:
136
156
  owner: host
137
157
  root: .claude/ext/sonar
138
158
  environment: dev
139
159
  compose: compose.yaml
140
160
  auth: token
141
- ci: { wiring: optional-follow-up }
161
+ credentials: []
162
+ projects: [{repository: "{{project}}", key: "{{project}}"}]
163
+ ci: {wiring: optional-follow-up, workflow: .github/workflows/ci.yml, token: SONAR_TOKEN, hostVar: SONAR_HOST_URL}
142
164
  ownerAction:
143
- needed: Provision the shared host Sonar project and its analysis credential through sealed custody.
165
+ 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
166
  reason: A fresh app declares its quality service without fabricating credentials or a successful analysis.
167
+ codecov:
168
+ provider: codecov
169
+ mode: hosted
170
+ purpose: Report application coverage through GitHub OIDC.
171
+ auth: oidc
172
+ target: 100
173
+ components: auto
174
+ required: true
175
+ ci: {wiring: optional-follow-up, workflow: .github/workflows/ci.yml}
176
+ ownerAction: none
177
+ dependabot:
178
+ provider: github
179
+ mode: hosted
180
+ purpose: Keep application dependencies and workflow actions current.
181
+ ecosystems: [npm, docker, github-actions]
182
+ schedule: {interval: weekly}
183
+ groups: {minorPatch: grouped, major: per-package}
184
+ ignore: ['@starci/*']
185
+ security: immediate
186
+ ownerAction: none
187
+ audit:
188
+ provider: npm
189
+ mode: local
190
+ purpose: Refuse high severity production dependency vulnerabilities.
191
+ level: high
192
+ omitDev: true
193
+ in: [release-gate, ci]
194
+ ownerAction: none
195
+ container-registry:
196
+ provider: ghcr
197
+ mode: hosted
198
+ purpose: Publish this app's deployment images with the workflow GitHub token.
199
+ host: {public: https://ghcr.io}
200
+ auth: github-token
201
+ projects: [{repository: "{{project}}", key: "{{project}}"}]
202
+ ci: {wiring: optional-follow-up}
203
+ 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}}