v0.6.5 — security hardening, Python-first Getting Started, architecture cleanup#32
Merged
Merged
Conversation
Restructure the portal Getting Started page to lead with the Python SDK and demote REST/curl to a "not using Python?" fallback. Step 3 now shows the same run two ways — a Jupyter notebook (cells, %pip, inline-rendered metrics) and a runnable script (run_simulation.py with a __main__ guard and SYNERGY_API_KEY from the env). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NPhdd5pXcgjdcJA9ZSdSzF
Closes the High/Medium findings in docs/SECURITY_AUDIT.md before release: - #1 IDOR: add object-level ownership checks to all read handlers (GetSimulation/GetResult/GetBatch/ListBatchSimulations) — a non-owner now gets the same 404 as a missing object (no existence leak), mirroring handleListArtifacts. New handlers_authz_test.go. - #2 dev-login backdoor: devLoginEnabled is now fail-closed (explicit PORTAL_DEV_LOGIN=1 only; no NODE_ENV default). Local compose opts in but binds the portal to 127.0.0.1. - #3 apiserver SA: base no longer shares the operator's cluster-wide SA (uses the no-RBAC default SA); prod keeps its scoped IRSA SA via the overlay (untouched). - #4 leaked credential: scrub the live sp_live_ token from the sample notebook (placeholder + generic localhost URL, cleared outputs). NOTE: the historical tokens still require server-side rotation. - #5 ref validation: validateInputRef rejects model/weather refs that aren't s3:// into the kind's bucket — blocks file://, bare paths, and cross-bucket reads, wired into both create paths (incl. per-variant). - #6 auth secret: portal refuses to start in production with an unset / placeholder BETTER_AUTH_SECRET (runtime instrumentation, not build); compose given a real local secret. - #7 runner: run as non-root UID 10001 (after the privileged build steps). - #8 batch cap: bound variants per batch (SP_MAX_BATCH_VARIANTS, 10000). Also drops a production bearer-token (magic-link) from an auth log line. Verified: go build/vet/test, portal tsc, manifest YAML validation, and an adversarial multi-agent review (GO, no bypass/regression). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NPhdd5pXcgjdcJA9ZSdSzF
Safe, behavior-preserving cleanups from a per-subsystem architecture audit (deep-module / domain-language / dedup lens): - Go: drop dead apiserver Config.PerUserCap; extract shared SELECT column lists + scan helpers in store; a pageParams() pagination helper; InsertSimulation returns (id, err) (state was always echoed); rename caps()->orDefault() and collapse deployName/scaledObjectName into resourceName() in the controller; fix a stale presign docstring. - Portal: align dashboard "jobs" vocabulary to the Simulation ubiquitous language; delete dead env.apiBaseUrl and api-keys last4(); rename the misleading last4 field to hashTail; single-source the created key name; hoist email-domain allow-list checks into one pure helper; add getRequiredPortalUser() to replace non-null user assertions. - Runner: delete dead Database.lookup_result; rename heartbeat()-> renew_lease() and _reconnect()->reconnect() to match the domain; don't record an artifact_uri when the upload failed; drop stale "worker" provenance now that worker/ is gone. - SDK: delete dead read_artifact_text from the StorageBackend; de-dup Variant model resolution; fix docstrings that wrongly required boto3 for the default presigned path. Verified: go build/vet/test, portal tsc, runner + SDK pytest all green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NPhdd5pXcgjdcJA9ZSdSzF
Bump portal, runner, and SDK to 0.6.5 and pin the prod kustomize overlay (operator/apiserver/portal/runner images) to the 0.6.5 tag the release CI publishes. The overlay also carries the apiserver SA comment update from the audit #3 split. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NPhdd5pXcgjdcJA9ZSdSzF
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Bundles the v0.6.5 release: a security pass that closes the independent audit findings, the Python-first Getting Started rewrite, and an audit-driven architecture cleanup.
1. Getting Started leads with Python (
docs(portal))Python SDK is now the primary path; REST/curl is demoted to a "not using Python?" fallback. Step 3 shows the same run two ways — a Jupyter notebook (cells,
%pip, inline-rendered metrics) and a runnable script (run_simulation.py,__main__guard,SYNERGY_API_KEYfrom env).2. Security remediation (
fix(security)) — closesdocs/SECURITY_AUDIT.md#1–#8PORTAL_DEV_LOGIN=1only); compose binds portal to127.0.0.1default; prod IRSA overlay untouched)sp_live_token scrubbed from the sample notebook (historical tokens still need rotation — see below)s3://-into-the-right-bucket ref validation (blocksfile://, bare paths, cross-bucket)BETTER_AUTH_SECRET(runtime guard, not build)SP_MAX_BATCH_VARIANTS, default 10000)Also drops a production magic-link bearer token from an auth log line.
3. Architecture cleanup (
refactor)24 safe, behavior-preserving items from a per-subsystem deep-module/domain-language audit: dead-code removal, SQL projection + scan-helper dedup, a pagination helper, controller renames, portal "jobs"→"Simulation" vocabulary alignment, runner
heartbeat→renew_lease+ a failed-upload artifact-URI correctness fix, SDK dedup + docstring fixes. 17 larger redesigns were deferred to follow-ups (see below).4. Release (
chore)Bump portal/runner/SDK to 0.6.5 and pin the prod overlay to the 0.6.5 images the release CI publishes.
Verification
go build/vet/test✅ · portaltsc✅ · runner + SDKpytest✅ · manifest YAML ✅ ·gofmt✅sp_live_…API tokens (one in git history, one that was in the working tree) and the Gmail SMTP app-password. The code scrub does not revoke them.gmail.comfrom any productionALLOWED_EMAIL_DOMAINS.Deferred follow-ups (tracked, not in this PR)
Audit #9 (gateway rate limiting), #10 (content-hash cache oracle), #11 (TLS posture — owned by SynergyPlusIAC); the
EligibleQueuedCRD field removal (needscontroller-gen, unavailable here); and 17 moderate architecture redesigns (typed response DTOs, single-source cache-resolution policy, KEDA ScaledObject watch, etc.).🤖 Generated with Claude Code
https://claude.ai/code/session_01NPhdd5pXcgjdcJA9ZSdSzF