Aman-Mittal opened a new pull request, #379:
URL: https://github.com/apache/fineract-backoffice-ui/pull/379
Closes every P1 from the release-readiness audit that this repository can
close on its own, so the dev-list proposal can be about the decisions the PMC
has to make rather than the work still outstanding. Tracked on #377.
| Blocker | State |
|---|---|
| **V1** — version is `0.0.0` | fixed |
| **D1** — no release documentation | fixed |
| **E1** — container cannot reach a backend | fixed, verified by running it |
| **E2** — compose defaults to a third-party demo host | fixed |
| **E3** — image build ignores the lockfile | fixed |
| **E4** — entrypoint drops config keys | fixed |
| **E5** — floating base image tags | fixed |
| **E8** — no CI job builds the image | fixed |
| **L1** — LGPL devDependency | fixed in #378 |
What remains for the PMC is genuinely theirs: artifact scope, the target
Fineract version, the final version number, and when the "not release-ready"
notice comes out. That notice stays.
## Business Value
The audit could say "not ready" but not "here is why it stays that way".
Every item above is something a deployer or a release manager hits directly.
The container one is the sharpest. Anyone who followed the documented
deployment got an application that loaded, showed a login screen, and could not
sign in — because every API call returned the application's own HTML. That is
the first experience an evaluating institution would have had, and it would
have looked like the software was broken rather than misconfigured. It now
works from `docker compose up`, and a CI job asserts it keeps working.
The release process matters for a different reason: the PMC is being asked
to approve a *process* as much as a payload. Writing it down before the vote
means reviewers can object to the method while it is still cheap to change,
rather than discovering it in the middle of a release.
## E1 — the container, verified rather than asserted
The audit found this by running the image; the fix is verified the same way,
from a clean container against a live Fineract:
```
GET / -> 200 text/html the application
GET /api/v1/offices (auth) -> 200 application/json Fineract's answer
GET /api/v1/offices (no auth) -> 400 Fineract's answer,
not the shell
GET /api/v1/probe.js -> 400 application/json proxied, not served
off disk
[{"id":1,"name":"Head Office","nameDecorated":"Head Office", ...
```
nginx now proxies `/api/` to the upstream Fineract, so the browser only ever
talks to this origin and the CSP keeps `connect-src 'self'` instead of being
widened per deployment.
Two things in that config are load-bearing and would look like mistakes
without the reason:
**`location ^~ /api/`.** A plain prefix match does not stop nginx evaluating
the static-asset regex below it, so any API path ending in `.js` would be
served from the filesystem — a 404 for a request that should have reached the
backend. That is the `/api/v1/probe.js` assertion above.
**`X-Forwarded-Proto` defaults to `https`, not `$scheme`.** Fineract decides
whether its channel requirement is met from that header. Measured against the
stock image, five requests each:
```
header absent 302 302 302 302 302 Location:
https://<host>/...
X-Forwarded-Proto: https 200 200 200 200 200
```
Forwarding `$scheme` produces a container that works only where TLS is
already terminated in front of it and redirects everywhere else. The
nginx→Fineract hop is itself TLS, so `https` is a true statement about the
connection Fineract is answering. `FINERACT_FORWARDED_PROTO` overrides it for
deployments behind another proxy.
## E2–E5 — the rest of the deployment
- **`npm ci`, not `npm install`.** CI has an entire job forbidding `npm
install` for the build; the image had been exempt from the one place it matters
most. Without it the image is not reproducible from the lockfile that the SBOM
and the licence scan both describe.
- **Both base images pinned by digest.** A release image that cannot be
rebuilt from its own Dockerfile a year later is not much of an artifact.
- **The compose file brings up its own Fineract and PostgreSQL.** It
previously defaulted to a public demo instance operated by someone else, so an
operator's first run sent the credentials they typed off-project.
- **The entrypoint writes `config.json` whole.** It used to write two keys
and drop the other three, which left `allowedApiOrigins` — backing a release
gate — unsettable in a container. Every key now has a default, so the file is
complete by construction. `RBAC_ENABLED` and `DEVELOPER_TOOLS_ENABLED` are
rejected unless exactly `true` or `false`, because `=no` would otherwise land
in the JSON as a truthy string and a deployment that believed it had turned
RBAC off would have it on.
## A gate that would have gone quiet
The GA `headers` gate reads the nginx server block. Renaming that file to
`.template` would have turned the gate `unknown` — and `unknown` did not block.
So it is repointed, **and** `ga-check.mjs` now fails on an undetermined
blocking gate.
A check that cannot read its input has not said yes. This repository has
already had a release gate that existed and was never run; a gate that silently
stops checking is the same failure wearing a green tick.
## E8 — the CI job that would have caught all of this
A 200 on `/` proves nothing. The new `Container Image` job builds the image,
starts a real Fineract, runs the container against it, and asserts:
- the application is served
- `config.json` carries every key the application reads
- `/api/v1/offices` answers as Fineract and **not** as the SPA shell —
content type is checked, because a wrong 200 is the failure mode
- an API path ending in `.js` is proxied rather than served locally
- security headers survive on a proxied response
## V1 — the version
`0.0.0` → `1.0.0-rc.1`, matching the audit's recommendation. The final
number is the PMC's to choose.
`npm run check:version` rejects `0.0.0` and non-SemVer, and on a tag build
asserts the tag names the same version `package.json` does — the quiet failure
being someone tagging `1.0.0` from a tree that still says `1.0.0-rc.1`, leaving
the tarball, the image and the SBOM disagreeing with the tag the vote was held
on. CI now runs on tags so it has something to compare.
**One correction to my own audit finding.** It claimed the version also
reaches `remoteEntry.json`. It does not — the many `0.0.0`s in that file are
native-federation's placeholders for internal chunks (`@nf-internal/chunk-*`),
unrelated to `package.json`. The SBOM claim is the one that holds, and it is
verified:
```
before: pkg:npm/[email protected]
after: pkg:npm/[email protected]
```
## D1 — the release process
`RELEASING.md` covers the TLP path end to end: signing key and KEYS, the
decisions the PMC has to make first, cutting and tagging, building the tarball
through `git archive` so nothing untracked can leak in, signatures and
checksums, staging on `dist.apache.org`, the vote thread with what a reviewer
is expected to check, and publishing.
Two steps are called out because they are the ones most easily got wrong:
**run RAT over the tarball, not the working tree** (a run over a git checkout
says nothing about the artifact), and **verify the tarball builds**.
It closes with the failures this project has actually had, so the next
release manager inherits a list rather than folklore.
`CHANGELOG.md` describes 1.0.0-rc.1 including the known limitations, not
only the functionality — the three features Fineract refuses on PostgreSQL, the
partially translated locales, the WCAG AA contrast shortfall, validation
against Fineract head rather than a pinned release, and the migration note
about route-level authorization.
## Documentation corrections
| Was | Is |
|---|---|
| Threat model: `rbacEnabled` is a build flag in `environment.ts` | a
runtime `config.json` key — with the trust implication now stated, since anyone
who can write that file can turn the client-side layer off without a rebuild |
| "Angular 21" in the threat model and `AGENTS.md` | Angular 22 |
| README links `GEMINI.md` | removed; the file does not exist and is not
tracked |
| `NOTICE` and README: "Copyright 2025" | 2025-2026 |
| README deployment section: three sketches, one showing an `/api/` proxy
that nginx did not implement | the deployment that now exists, with the full
environment-variable table |
## Testing
| Gate | Result |
|---|---|
| `lint:prune`, HTML lint | pass |
| `test:eslint-rules` | 26/26 |
| `format:check` | pass |
| `i18n:check`, `check:icons` | pass |
| `check:internal-endpoints`, `check:route-permissions` | pass |
| **`check:version`** | pass — and verified to fail on a mismatched tag |
| `typecheck:e2e`, `api:surface` | pass |
| `check-license.sh`, `check:licenses`, `check:licenses:selftest` | pass |
| `build` | pass |
| Unit tests | **1093 SUCCESS** |
| `ga:check` | 8/9, **0 blocking, 0 undetermined**; adapter backlog
unchanged at 416 |
| Container image | built and run against a live Fineract; all five
assertions above verified by hand before the CI job was written |
## Breaking changes
**For container deployments only**, and deliberate:
`FINERACT_API_URL` now names the **upstream** Fineract as reachable *from
the container*, not a browser-visible URL. A deployment that set it to a
browser-facing address must change it to the address nginx should proxy to.
This is the change that makes the container work at all — the previous meaning
could not, because the CSP refused the cross-origin request it implied.
`deploy/nginx.conf` is replaced by `deploy/nginx.conf.template`. A
deployment that mounted its own `nginx.conf` over the old path is unaffected;
one that copied the file as a starting point should re-copy.
Nothing changes for the application itself.
--
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]