Skip to content

fix(dtrack): source JDBC host/port from externalDatabase.existingSecret#113

Open
dragonpaw wants to merge 1 commit into
artifact-keeper:mainfrom
dragonpaw:fix/dtrack-jdbc-host-port-from-existing-secret
Open

fix(dtrack): source JDBC host/port from externalDatabase.existingSecret#113
dragonpaw wants to merge 1 commit into
artifact-keeper:mainfrom
dragonpaw:fix/dtrack-jdbc-host-port-from-existing-secret

Conversation

@dragonpaw

@dragonpaw dragonpaw commented May 20, 2026

Copy link
Copy Markdown
Contributor

Summary

When postgres.enabled=false and externalDatabase.existingSecret is set (the canonical external-DB path), templates/dtrack-deployment.yaml builds ALPINE_DATABASE_URL from externalDatabase.host / externalDatabase.port plain-string values. Operators following the existingSecret pattern who omit those plain values get an empty-host JDBC URL — jdbc:postgresql://:5432/dependency_track — which JDBC interprets as localhost, and dtrack then fails on startup with Connection refused.

This PR projects host/port out of the operator-provided Secret into two leading env vars (_DTRACK_DB_HOST, _DTRACK_DB_PORT) and references them from ALPINE_DATABASE_URL via Kubernetes $(VAR) expansion. Two new values let operators point at custom keys in the Secret:

externalDatabase.existingHostKey  (default "POSTGRES_HOST")
externalDatabase.existingPortKey  (default "POSTGRES_PORT")

Mirrors the precedent in #110 (existingPasswordKey). Strictly additive: when existingSecret is unset, the literal host/port substitution is preserved — helm template output is byte-identical for the in-cluster-postgres and inline-host/port paths.

A longer-term alternative would be to consume the full DATABASE_URL the backend already reads from the Secret (parse postgresql://...jdbc:postgresql://... in the template). Happy to do that follow-up if you'd prefer a single source of truth across both deployments.

Reproducer (before this PR):

helm template ak charts/artifact-keeper \
  --set postgres.enabled=false \
  --set externalDatabase.existingSecret=mysecret \
  --set externalDatabase.username=u \
  --set secrets.jwtSecret=jwt --set secrets.s3AccessKey=ak --set secrets.s3SecretKey=sk \
  --set opensearch.auth.password=op \
  --set dependencyTrack.enabled=true --set dependencyTrack.adminPassword=adminpw

Renders ALPINE_DATABASE_URL: "jdbc:postgresql://:5432/dependency_track". After this PR the same command renders the URL with $(VAR) expansion against the two new env vars sourced from mysecret.

Test Checklist

  • Helm template renders without errors (helm lint clean)
  • Terraform validates/plans cleanly (N/A — chart-only change)
  • Manually verified renders across four value combinations
  • Rollback strategy documented (pure additive values; revert is safe)

Infrastructure

  • Helm: helm template renders correctly: defaults / inline external DB / existingSecret only / existingSecret + custom host/port keys
  • Helm: helm-docs regenerated (README values table updated)
  • Terraform: terraform validate passes (N/A)
  • Terraform: terraform plan shows expected changes (N/A)
  • ArgoCD: Application manifests are valid (N/A)
  • N/A - documentation only

Closes #151

@brandonrc

Copy link
Copy Markdown
Contributor

Thanks for this. Now that several chart PRs (including the v1.2.0 alignment #145 and the load-bearing image-tag change #78) have landed on main, this branch has merge conflicts. Could you rebase onto the latest main, resolve them, run cd charts/artifact-keeper && helm-docs if values changed, and push? CI will re-run after.

(The red SonarCloud check is a known non-blocking fork limitation and can be ignored.)

When `postgres.enabled=false` and `externalDatabase.existingSecret` is set
(the canonical external-DB path), `templates/dtrack-deployment.yaml` built
`ALPINE_DATABASE_URL` from `externalDatabase.host` / `externalDatabase.port`
plain-string values. Operators following the existingSecret pattern who
omit those plain values get an empty-host JDBC URL —
`jdbc:postgresql://:5432/dependency_track` — which JDBC interprets as
`localhost` and dtrack then fails on startup with `Connection refused`.

This change projects host/port out of the operator-provided Secret into
two leading env vars (`_DTRACK_DB_HOST`, `_DTRACK_DB_PORT`) and references
them from `ALPINE_DATABASE_URL` via Kubernetes `$(VAR)` expansion. Two new
values let operators point at custom keys in the Secret:

  externalDatabase.existingHostKey  (default "POSTGRES_HOST")
  externalDatabase.existingPortKey  (default "POSTGRES_PORT")

Mirrors the precedent set by `externalDatabase.existingPasswordKey`
(artifact-keeper#110). Strictly additive: when `existingSecret` is unset, the literal
host/port substitution is preserved — `helm template` output is
byte-identical for the in-cluster postgres and inline-host/port paths.
@dragonpaw dragonpaw force-pushed the fix/dtrack-jdbc-host-port-from-existing-secret branch from 11d74ea to 337bb6b Compare June 3, 2026 23:39
@dragonpaw

Copy link
Copy Markdown
Contributor Author

Rebased onto the latest main as requested — conflicts resolved and helm-docs regenerated for the new externalDatabase.existingHostKey/existingPortKey values. Filed and linked a tracking issue (#151) so require-linked-issue passes. Re-verified the render: with externalDatabase.existingSecret set, ALPINE_DATABASE_URL now expands $(_DTRACK_DB_HOST):$(_DTRACK_DB_PORT) from the Secret; default paths render byte-identical. Ready for another look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dtrack JDBC URL has an empty host when using externalDatabase.existingSecret -> Connection refused

2 participants