fix(config): resolve the Caldera REST connection from core config - #33
Merged
HackedRico merged 1 commit intoAug 28, 2026
Merged
Conversation
The plugin hardcoded ADMIN123 as its API key fallback and localhost as its host. Caldera hashes api_key_red and api_key_blue at boot and authenticates by verifying the submitted plaintext against the stored hash, so ADMIN123 only works on a --insecure boot, and only because the stored hash happens to be a hash of it. Every server whose conf/local.yml was generated gets a random key instead, and the resulting 401 was close to undiagnosable: the tool wrapped it in a successful result and core_health_check reported "Caldera API is UP!" because the error object it type-checked was a dict. Build the URL from the host and port caldera binds to, mapping a wildcard bind to loopback since 0.0.0.0 is not a routable destination and bracketing IPv6 literals. Check the API key by asking caldera's own hasher the same question its auth service asks, in-process and without a request, and report a rejected key at boot and on the splash page instead of failing silently later. The check is diagnostic only. The key is returned either way, and an explicitly configured one is never swapped for a value the operator did not choose. It is also skipped when CALDERA_URL points elsewhere, since a remote server's keys are not ours to verify. Both env vars keep top precedence for deployments where MCP cannot reach the address caldera binds to. get_env now forwards the resolved values rather than re-reading the environment, so subprocesses receive a normalised URL; previously a CALDERA_URL without the /api/v2/ suffix reached the child raw, and the cti_pipeline server hit the login page and got a JSONDecodeError on a 200 HTML body. Drop the two Caldera entries from .env.example. CALDERA_URL there pinned port 8888 and outranked the port caldera actually listens on, so copying the file broke any deployment that had moved off the default port.
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.
Description
app/config.pyhardcodedADMIN123as the API key fallback andlocalhostas the host, ignoring what CALDERA is actually configured with.CALDERA argon2-hashes
api_key_redandapi_key_blueat boot (server.pycallsapply_config(..., apply_hash=True), which also rewritesconf/<env>.yml), then authenticates by verifying the submitted plaintext against the stored hash. SoADMIN123works only on a--insecureboot, and only because the stored hash happens to be a hash of it. Any server whoseconf/local.ymlwas generated gets a random key instead, and every MCP call 401s.That 401 was close to undiagnosable.
make_get_requestwraps it in a successful tool result, andcore_health_checkreported"Caldera API is UP!"because the error object it type-checked is itself a dict.This PR:
hostandportCALDERA binds to, mapping wildcard binds to loopback (0.0.0.0is not a routable destination) and bracketing IPv6 literals.core_health_checkreporting UP on a non 200.The key check is diagnostic only. The key is returned either way, and an explicitly configured one is never swapped for a value the operator did not choose. It is skipped when
CALDERA_URLpoints elsewhere, since a remote server's keys are not ours to verify.Both env vars keep top precedence.
get_env()now forwards the resolved values rather than re-reading the environment, so subprocesses receive a normalised URL. Previously aCALDERA_URLwithout the/api/v2/suffix reached the child raw, and the cti_pipeline server (which only appends) hit the login page and got aJSONDecodeErroron a 200 HTML body.Also drops the two Caldera entries from
.env.example.CALDERA_URL=http://localhost:8888there pinned port 8888 and outranked the port CALDERA actually listens on, so copying the file broke any deployment that had moved off the default.Note for reviewers: this deliberately does not read
api_key_redas a credential. That approach cannot work on current CALDERA, and a regression test asserts the resolver never returns an$argon2id$value.Type of change
How Has This Been Tested?
Against a live CALDERA 5.3.0 on
conf/default.yml:.env: resolveshttp://127.0.0.1:8888/api/v2/,GET /api/v2/healthreturns 200 with"access": "RED".auth_svc.request_has_valid_api_key, and the resolver's verdict matches it.api_key_red's raw hash returns 401, confirming a hashed config value is never a usable credential.caldera_corespawned over stdio exactly as the workflow spawns it: 20 tools exposed,core_health_checkreturns UP.core_health_checkwith a deliberately wrong key:mainreturns"Caldera API is UP!", this branch returns"... is not usable: ... 401: Unauthorized".CALDERA_URL:maingets 200text/htmland aJSONDecodeError, this branch gets 200application/json.Suite: 28 new tests in
tests/test_config.pycovering wildcard and IPv6 and narrowed binds, port and URL overrides, hashed and plaintext and unreadable configs, and subprocess env propagation. Full run shows no regressions (failures are a strict subset of themainbaseline, all pre-existing spaCy and CTI issues).flake8 --select=E9,F63,F7passes with no new findings.Not verified:
hook.py'senable()on a live boot, since the running server loads the unmodified plugin. The resolution and log formatting were tested directly.Checklist: