Tags: ubc/charts
Tags
feat(operations-hub): SAML SP configuration support (#72) * feat(operations-hub): SAML SP configuration support The chart had no way to express SAML settings, so SAML_SP_ENTITY_ID, SAML_SP_BASE_URL, SAML_SP_CERT_PATH and SAML_SP_KEY_PATH were never set in the pod. The app treats an unconfigured SP as absent and returns 404 from /auth/saml/metadata, which blocked registering the service with UBC IAM. The env list in operations-hub.podEnv is closed and the deployment hardcodes its volumes, so there was no escape hatch to work around this from a values file. Adds an app.saml block, off by default. Registering an SP is a two-way exchange, so it is usable in two stages: the four SP keys alone publish metadata, and idpMetadata is added later from what IAM returns to enable sign-in. The keypair comes from Vault via ExternalSecret, following the existing db secret, so the private key stays out of the configuration repo. Cert, key and IdP metadata are projected into one directory, with their paths derived from a single mountPath helper so env and volume cannot drift apart. Claude-Session: https://claude.ai/code/session_01Mjtg4ssz6G6TnacYsRCDEK * test(operations-hub): add render-assertion harness * feat(operations-hub): add IdP metadata fetch script * fix(operations-hub): harden IdP metadata fetch script per review - write_atomic: explicitly set temp file mode 0644 before rename, so output readability by the app container is stated rather than inherited from mkstemp's default 0600. - baseline fallback write is now wrapped in its own try/except so a failure there logs a clean ERROR and returns 1 instead of leaking a raw traceback. - test-fetch.sh: tests 3 and 4 now assert the fallback content was actually written (grep -q baseline), not just that exit was 0, so a regression in validate() can no longer pass vacuously. * feat(operations-hub): add IdP auto-fetch values and template guard * fix(operations-hub): handle whitespace-only idpEntityId and document idpFetchTimeout - Use trim() in guard to reject whitespace-only values, closing the bypass - Add regression test with whitespace-only idpEntityId - Document idpFetchTimeout with units and fallback behavior * fix(operations-hub): make idpEntityId guard nil-safe and add test coverage - Use default "" to convert nil to empty string before trim() - Fixes regression where explicit null caused type error instead of clear message - Add regression test with explicit null value - Suite now covers: absent key, empty string, whitespace, and explicit null * refactor(operations-hub): give IdP metadata its own mount * fix(operations-hub): gate saml-idp volume/mount on app.saml.enabled The IdP volume and mount were gated only on idpMetadata/idpMetadataUrl, but the ConfigMap backing them is gated on enabled AND idpMetadata. With enabled: false and idpMetadata still set, the Deployment referenced a ConfigMap that never rendered, leaving the pod stuck in ContainerCreating. Nest both blocks under the same enabled check the SP-keypair volume and SAML_IDP_METADATA_PATH env var already use. * feat(operations-hub): fetch IdP metadata at pod start * fix(operations-hub): apply resources to init container, cover autofetch fallback branch, default idpFetchTimeout Post-review fixes for the IdP metadata init container: - Add the same {{- with .Values.resources }} block to the init container that the app container already has, so a values file setting resources applies to the whole pod instead of silently skipping the init container. - Default idpFetchTimeout to 15 before quoting, so a nulled value doesn't render an empty string that crashes the fetch script's int() parse before its try block -- that turned a recoverable fetch failure (baseline present) into an unrecoverable one. - Add saml-autofetch-no-baseline.yaml and six new assertions covering the previously-untested branches: IDP_ENTITY_ID reaching the init container, the init-writes-where-the-app-reads invariant, and both the baseline-present and baseline-absent IDP_BASELINE_PATH/volume paths. Suite: PASSED 24 (was 18). Byte-identical gate still holds. * fix(operations-hub): close SAML IdP metadata integrity and safety gaps Final review found four issues in the IdP auto-fetch feature: - values.yaml documented idpMetadataUrl as replacing the pasted idpMetadata baseline ("instead of pasting it above"), contradicting the comment five lines above and the design goal that an unreachable IdP must never take local login down with it. Reworded to make clear the two work together. - fetch-idp-metadata.py passed IDP_METADATA_URL to urlopen unfiltered, so http:// silently dropped TLS (the only integrity control besides the pinned entity id) and file:// read a local path. The script now rejects any non-https scheme before fetching, raising into the existing fallback path rather than adding a new exit. The Helm guard now rejects a non-https or whitespace-only idpMetadataUrl at render time too, since a whitespace string is truthy in Go templates and would otherwise render IDP_METADATA_URL: " ". test-fetch.sh's file:// malformed-XML fixture is split into a scheme-rejection case and a genuine malformed-XML-over-https case so no coverage is lost. - configmap-saml-fetch.yaml's .Files.Get had no `required`, so a missing packaged script rendered an empty ConfigMap, python3 exited 0 on it, and the pod went Running/Ready with SSO silently broken. Wrapped in `required` so this is now a loud template error. - The baseline document was written on the fetch-failure fallback path without being run through the same validator as the fetched document, so a bad pasted baseline was only discovered during the outage that forced the fallback. It's now validated first; a failure is logged at ERROR with the reason but the file is still written -- fail-open posture unchanged. operations-hub/tests/run.sh: 24 -> 26 PASSED. Hard gate (saml-off render) remains byte-identical. In-pod test-fetch.sh: 12 PASSED, no skip. Claude-Session: https://claude.ai/code/session_01Mjtg4ssz6G6TnacYsRCDEK
EDIT operations-hub add email config The app supports other configurable env vars for the mail, we're supporting: MAIL_SERVER, MAIL_PORT, MAIL_USE_TLS, MAIL_USE_SSL Other vars like APP_NAME and MAIL_DEFAULT_SENDER is fine with their default values, so unless there's a need for it, I'll leave them out of deployment config for now.
ADD operations hub initial chart New internal app from Jason (LTIC IP ranges only access): https://repo.code.ubc.ca/lthub/operations-hub
feat(mariadb): default-on reconnectOnAuthError for replica auth self-… …heal (#70) Render spec.replication.replica.recovery when either recovery.enabled OR recovery.reconnectOnAuthError is set (previously enabled-only), emit the actual enabled value, and add reconnectOnAuthError (default true). Lets a replica stuck on repl auth error 1045 self-heal via the operator without enabling the heavy backup-rebuild recovery. Requires the operator's reconnectOnAuthError build. Bump 0.1.27 -> 0.1.28.
feat(webwork): extraVolumes/extraVolumeMounts (0.3.5) (#68) Generic extraVolumes/extraVolumeMounts on all webwork containers (web + workers), mirroring extraEnv. Enables mounting a secret-backed file (e.g. the WeBWorK 2.20 native SAML2 SP signing keypair for $saml2{sp}{certificate_file}/{private_key_file}). Registered in values.schema.json (root additionalProperties:false).
feat(moodle): make shibd health probes configurable (0.3.20) (#69) * feat(webwork): extraVolumes/extraVolumeMounts (0.3.5) Generic extraVolumes/extraVolumeMounts on all webwork containers (web + workers), mirroring extraEnv. Enables mounting a secret-backed file (e.g. the WeBWorK 2.20 native SAML2 SP signing keypair for $saml2{sp}{certificate_file}/{private_key_file}). Registered in values.schema.json (root additionalProperties:false). * feat(moodle): make shibd health probes configurable; bump to 0.3.20 The shibd liveness/readiness probes were hardcoded to tcpSocket:1600, which does not answer probe connects cleanly for shibd's listener. Instances had no way to override it, so operators patched the live Deployment by hand to exec: pgrep -x shibd — leaving un-versioned drift that collides with the chart under ArgoCD server-side diff (the two handler types merge into an invalid probe). Render the probes from .Values.shib.livenessProbe/readinessProbe, defaulting to the existing tcpSocket:1600 via the template's default function. The default is intentionally kept in the template, not in values.yaml: Helm deep-merges values, so a populated values default would merge with a per-instance override and reintroduce the two-handler bug. values.yaml keeps the keys empty. No change for existing users (default unchanged). Verified: default render -> tcpSocket:1600; exec override -> exec only (single handler).
chore(webwork): remove dead values + document real LTI config (0.3.4) - delete ltiClient/caliper/stage/rHost (never read by current templates) and shibd.odbc.port/database/user/password (shibd DB coordinates come from db.auth + provider wiring) - schema: the removed keys are no longer allowed — values files still carrying them fail the render (see 0.3.3 -> 0.3.4 upgrade note) - README: LTI 1.3 section now describes the actual mechanism (webworkFiles.localOverrides + ESO env vars), not the dead ltiClient list
PreviousNext