Aman-Mittal commented on issue #377:
URL:
https://github.com/apache/fineract-backoffice-ui/issues/377#issuecomment-5308037696
## Staying current with Fineract, and the Docker Hub question
Answering the two engineering questions raised alongside this release.
### 1. Does the UI stay current with the head of Fineract main?
**Today, yes — and this was verified rather than assumed.** The spec inside
the running `apache/fineract:latest` container was extracted and diffed against
the committed contract:
```
committed public/api/fineract.json info.version 1.16.0-SNAPSHOT | paths
594 | operations 958
spec inside apache/fineract:latest info.version 1.16.0-SNAPSHOT | paths
594 | operations 958
operations in head but not committed: 0
operations committed but gone from head: 0
```
`.github/workflows/api-spec-sync.yml` is what keeps it that way: weekly,
resolves `apache/fineract:latest` to a **digest**, short-circuits if the digest
has not moved, otherwise reads the spec out of the image without booting
Fineract, regenerates the client, writes a provenance record, and opens a PR.
`permissions: {}` at workflow level. The real-backend E2E job also runs against
`latest`, so behavioural drift is exercised on every PR, not just contract
drift.
Of the platform's 958 operations the UI calls **564 across 142 services**,
pinned in `src/app/core/adapters/api/api-surface.json` and enforced by `npm run
api:surface` in CI. Drift in either direction fails the build.
**Three gaps worth closing:**
| # | Check | Why |
|---|---|---|
| 1 | Nightly `E2E (real Fineract)` on `main` | Head-drift is only exercised
when someone opens a PR. A quiet week runs nothing. |
| 2 | Make the spec-sync compile-check failure loud in the PR body and job
summary | Keep `continue-on-error` — an upstream removal must still open its PR
— but a break should not read as green. |
| 3 | Daily rather than weekly sync | The digest short-circuit already makes
an unchanged run cost seconds. |
### 2. "The first release may need to be retrospective to 1.15"
**This is the real gap, and nothing currently covers it.** Everything above
validates against *head*, and the committed spec reports `1.16.0-SNAPSHOT`.
Whether all 564 operations the UI calls exist in **1.15** is presently
**unknown**.
| # | Work | Why |
|---|---|---|
| 4 | `scripts/check-api-compatibility.mjs <spec>` — diff `api-surface.json`
against a target Fineract spec, fail on any operation the UI calls that the
target does not serve | The single most important unanswered question if 1.15
is the target. `scripts/spec-diff-summary.mjs` already has most of the
machinery. |
| 5 | A compatibility-matrix E2E job running the `backend` project against a
pinned `apache/fineract:1.15.0` | Contract compatibility is necessary but not
sufficient; behaviour differs too. |
| 6 | A supported-versions table in the README, generated from whichever
versions the matrix actually runs | So a deployer can see what was tested
rather than infer it. |
**If 1.15 is the release target, item 4 should be green before the vote.**
### 3. Deploying alongside Fineract on Docker Hub
The image **builds** — `docker build -f deploy/Dockerfile .` → exit 0, 107
MB — but is not deployable as shipped. Running it:
```
GET / → 200 text/html (the SPA)
GET /config.json → {"fineractApiUrl":"/api/v1", …}
GET /api/v1/authentication → 200 text/html, 7546 bytes ← the SPA shell,
not Fineract
```
`deploy/nginx.conf` has no `location /api/` proxy, so every API call falls
through `try_files` to `index.html`. The alternative — the compose file setting
an absolute cross-origin `FINERACT_API_URL` — is blocked by the CSP that same
file serves (`connect-src 'self'`, confirmed in the response headers).
Setting `FINERACT_API_URL` also reduces `config.json` from five keys to two:
```
before: fineractApiUrl, defaultTenant, rbacEnabled, institutionType,
developerToolsEnabled
after: fineractApiUrl, defaultTenant
```
`ConfigService` merges over its defaults, so `rbacEnabled` still lands
`true` — **this is not an RBAC bypass**, and that was checked in source rather
than assumed. But `allowedApiOrigins` (which backs a blocking GA security
gate), `institutionFeatures` and `nav` overrides become unconfigurable in a
container.
**In order, before anything is published:**
| # | Work |
|---|---|
| 7 | Add the API proxy to `deploy/nginx.conf` so `fineractApiUrl:
"/api/v1"` is same-origin and satisfies `connect-src 'self'` |
| 8 | Point the compose file at a local Fineract service, not a third-party
demo host |
| 9 | `npm ci` in the Dockerfile; pin both base images by digest |
| 10 | Let the entrypoint **merge** `config.json` rather than overwrite it |
| 11 | A CI job that builds the image, runs it, and asserts `GET /api/v1/…`
is proxied and not HTML |
| 12 | `HEALTHCHECK`, non-root nginx, drop the obsolete `version: '3.8'` |
| 13 | A publish workflow (tag → multi-arch build → provenance → Docker
Hub), gated on the PMC vote |
Item 11 is the one that matters most long-term: this audit found the proxy
gap in ten minutes because it ran the container. CI never has.
### 4. On "the security setup is better than existing solutions"
That claim needs a defensible basis, so here is the evidence, all verified
in this audit:
| Property | This application |
|---|---|
| Route-level permission enforcement | Yes — `permissionGuard` on protected
routes, returning a real Access Denied page rather than a silent dashboard
bounce |
| Navigation/route drift prevention | Yes — a CI check that fails on
disagreement and exits 1 rather than passing vacuously if it parses nothing |
| Permission codes validated against the platform catalogue | Yes — 223/223
real, checked against the live 699-code catalogue |
| Two-factor authentication | Yes, with a dedicated E2E stack and a mail
catcher |
| CSP without `unsafe-eval` | Yes, shipped in `deploy/nginx.conf` |
| API-origin allow-list for endpoint override | Yes — a blocking GA gate |
| Authorization header restricted to the API origin | Yes — a blocking GA
gate |
| No sanitizer bypasses or raw HTML sinks | Yes — a blocking GA gate |
| Production dependency vulnerabilities | 0 |
| Published threat model | 61 KB, in-repo |
| Signed-commit enforcement on PRs | Yes |
| Backend refusal asserted in tests | Yes — E2E confirms Fineract itself
refuses the restricted user's operation |
The honest framing for a vote is **"defence-in-depth the previous UI did not
have, with Fineract Core still the authoritative boundary"** — not "more
secure". A frontend cannot be the security boundary, and `DOCS/RBAC.md`,
`security.md` and the guard's own doc comment are already careful to say so.
That framing should not be softened to make the release read better.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]