Skip to content

GitLab CI migration — handover notes

Date: 2026-05-13
Migration status: Complete for all currently-built modules. Agents own their CI pipeline from here.


What changed from GitHub Actions

Every module that was on GitHub Actions now has equivalent GitLab CI jobs generated under .gitlab/ci/mod-NNN.gitlab-ci.yml in its repo. Each module file includes a shared template from totara-bank/bank-platform and defines two jobs:

  • mod-NNN-mr — MR validation (typecheck, lint, unit tests, policy tests). Fires on merge request events only. No deploy, no artefact upload, no wiki handoff.
  • mod-NNN-deploy — Full deploy pipeline. Fires on push to main (or manual web trigger). Runs: install → typecheck → lint → tests → build → deploy (Pulumi/Serverless/Cloudflare) → integration tests → writes Built handoff → smoke test → writes Deployed handoff.

Templates live in bank-platform/.gitlab/ci/templates/:

Template Used by
lambda.gitlab-ci.yml bank-core, bank-kyc, bank-aml, bank-payments, bank-credit, bank-app (Lambda modules), bank-platform
frontend.gitlab-ci.yml bank-app (frontend/Cloudflare modules)
iac.gitlab-ci.yml bank-platform (infrastructure modules)
risk-platform.gitlab-ci.yml bank-risk-platform (all SD06 modules)

Known issue: missing changes: path guards

Every repo except bank-risk-platform still has unconditional deploy rules on every module job. This means every push to main in your repo runs every module's deploy job, regardless of what changed. This burned GitLab compute minutes during the migration.

Do not make a bulk fix commit. Add the guard naturally when you next push a real code change to a module. The pattern is:

# In .gitlab/ci/mod-NNN.gitlab-ci.yml — replace the existing push rule:
  rules:
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
      changes:
        - MOD-NNN-your-module-name/**/*   # only run when this module's source changes
    - if: '$CI_PIPELINE_SOURCE == "web"'
      when: manual
      variables:
        STAGE: ${DEPLOY_STAGE:-dev}

The manual web trigger (CI_PIPELINE_SOURCE == "web") remains unconditional so you can always re-deploy a specific module from the GitLab UI without touching code.

bank-risk-platform already has changes: guards applied to all 11 modules (ca3d624).


Handoff mechanism — how CI advances build_status in bank-wiki

When a deploy job completes successfully it writes a .handoff.md file into docs/handoffs/ in your repo and pushes it back to main. The bank-wiki agent polls for these files and runs:

python3 scripts/update-wiki.py --module MOD-NNN --status Built|Deployed \
  --commit SHA --repo your-repo-name

This advances build_status in source/entities/modules/MOD-NNN.yaml and recompiles the wiki. You do not need to edit wiki YAML manually for build status — CI owns that field.


Per-SD status and outstanding items

SD01 — Core Banking (bank-core)

Metric Value
CI jobs 18 (lambda template)
Deployed 19/20
changes: guards None — add when next committing to any module

Outstanding: MOD-118 has no source directory — not yet built.


SD02 — KYC Platform (bank-kyc)

Metric Value
CI jobs 8 (lambda template)
Deployed 8/9
changes: guards None — add when next committing to any module

Outstanding: MOD-096 has no source directory — not yet built.


SD03 — AML Monitoring (bank-aml)

Metric Value
CI jobs 3 (lambda template)
Deployed 3/4
changes: guards None — add when next committing to any module

Outstanding: MOD-019 has no source directory — not yet built.


SD04 — Payments (bank-payments)

Metric Value
CI jobs 10 (lambda template)
Deployed 10/26
changes: guards None — add when next committing to any module

Outstanding: 16 modules (MOD-026/061/067/081/084/114/122/123/124/135/136/137/144/145/149/154) have no source directory — not yet built. CI jobs exist only for the 10 Deployed modules.


SD05 — Credit (bank-credit)

Metric Value
CI jobs 12 (lambda template)
Deployed 12/17
changes: guards None — add when next committing to any module

Outstanding: 5 modules (MOD-121/132/162/163/167) have no source directory — not yet built.


SD06 — Risk Platform (bank-risk-platform)

Metric Value
CI jobs 11 (risk-platform template)
Deployed 8/32
changes: guards All 11 applied (ca3d624)

Three modules incomplete — these are your immediate CI responsibility:

Module Status Issue Action needed
MOD-041 Not started SCP resolved in code (4b9855e) — bucket moved to MOD-104. Blocked on MOD-104 shipping bank-merchant-assets-{env} SD07 has the handoff (MOD-041-needs-MOD-104-merchant-assets-bucket.handoff.md). Re-trigger after MOD-104 deploys bucket.
MOD-056 Not started No S3 in Pulumi stack — re-clears on retrigger Re-trigger directly; no infrastructure prerequisite
MOD-080 Built Bucket already provisioned (6a21dae) — re-trigger to advance to Deployed Re-trigger directly

DCM ownership context: SF_ROLE (the CI service account) cannot self-grant ownership of DCM projects pre-created as BANK_NONPROD_RISK_ROLE. The workaround sets HAS_DCM=false and HAS_DBT_PROJECT=false, routing these modules through the legacy dbt build path instead of snow dcm plan/deploy and snow dbt deploy/execute. See .gitlab/ci/mod-041.gitlab-ci.yml comments for full explanation.

Long-term resolution (DCM): grant SF_USER the BANK_NONPROD_RISK_ROLE role in Snowflake, then flip HAS_DCM and HAS_DBT_PROJECT back to true for these three modules.

SCP blocker — resolved for MOD-041, MOD-056, MOD-080

SD06 agent resolved via commit 4b9855e (2026-05-13 09:14 +1200): S3 bucket creation removed from MOD-041's Pulumi stack and delegated to MOD-104 (bank-platform), which runs under a principal exempt from the SCP. The same pattern was applied earlier for MOD-080 in 6a21dae. MOD-056 has no S3 resources — it clears on retrigger without any prerequisite.

Current blocking state per module:

Module Status Remaining blocker
MOD-041 Waiting on MOD-104 MOD-104 must provision bank-merchant-assets-{env} first. Handoff delivered to SD07 (MOD-041-needs-MOD-104-merchant-assets-bucket.handoff.md in bank-platform/docs/handoffs/). Re-trigger mod-041-deploy after MOD-104 ships.
MOD-056 Ready to retrigger No S3 dependency. Re-trigger directly from GitLab UI (web trigger).
MOD-080 Ready to retrigger Bucket already provisioned. Re-trigger to advance from Built → Deployed.

23 further Not-started modules (MOD-033/034/036/037/055/057/058/060/088/089/092/094/095/ 101/105/106/107/147/150/152/165) have no source directory — not yet built. They have no CI jobs. Add them to .gitlab-ci.yml when code is ready.


SD07 — Data Platform (bank-platform)

Metric Value
CI jobs 23 (lambda + iac templates)
Deployed 23/26
changes: guards None — add when next committing to any module

Outstanding: MOD-087, MOD-093, MOD-168 have no source directory — not yet built.


SD08 — App (bank-app)

Metric Value
CI jobs 6 (lambda + frontend templates)
Deployed 6/34
changes: guards None — add when next committing to any module

Outstanding: 28 modules have no source directory — not yet built. The 6 Deployed modules cover the current app shell and back-office (MOD-049/050/052/068/069 + one more).


Pipeline from e16ffcf — outcome

Commit e16ffcf (2026-05-13 07:18 +1200) added changes: guards to the 8 already-Deployed modules but left MOD-041/056/080 with unconditional push rules. That commit triggered a 3-job pipeline for those three modules. Six minutes later, ca3d624 added guards to MOD-041/056/080 too — but the pipeline was already in flight. ca3d624 fires zero jobs (only CI config files changed).

The pipeline failed. MOD-041-deploy failed at Pulumi up (~45 min in) with an AWS SCP deny on s3:CreateBucket for bank-dev-merchant-assets (see SCP blocker above). MOD-056 and MOD-080 were likely cancelled or similarly blocked. No ci(handoff) commits were written. Build statuses for MOD-041/056/080 are unchanged from before the pipeline ran.


CI template change log (migration period)

Key fixes made to bank-platform/.gitlab/ci/templates/risk-platform.gitlab-ci.yml:

Commit Change Reason
6fa4aa4 Smoke test made conditional on file existence Modules without verify-deployment.mjs were failing
e5044b7 apply-ddl guarded by jq script-existence check HAS_DCM=false modules without the script were failing
200217f DCM Phase 2 ENV_ROLE grant made non-fatal GRANT OWNERSHIP exits non-zero even on self-grants; Phase 2 was killing all HAS_DCM=true jobs

These fixes are in the shared template. All SD06 modules benefit automatically.