Repository navigation
Project ConfigMap and Secret consumers by mode (#410 P1, core) - #503
Merged
Merged
Conversation
There was a problem hiding this comment.
🟢 Approved
No active review issues remain for the ConfigMap and Secret consumer diagnostics foundation.
No open issues 🎉
What changed in this PR
Adds the core foundation for ConfigMap and Secret consumer diagnostics in korvid (#501, part of #410). It identifies declared Pod consumers by consumption mode; the UI, shared evidence renderer, and wiring follow in #502.
Changes:
- Shares configuration-reference extraction with the relationship graph, preserving fact ordering and field paths.
- Projects consumers by environment, volume, subPath, unmounted-volume, and image-pull modes, including container categories.
- Adds bounded namespace-scoped evidence reads, run-token tracking, and tests for incomplete reads, absence, recreation, and exclusion of literal environment values.
| File | Description |
|---|---|
tests/test_optional_extras.py |
Checks that new modules import without optional extras. |
tests/k8s/test_config_references.py |
Covers reference forms, ordering, and malformed entries. |
tests/core/test_config_propagation.py |
Covers read budgets, evidence outcomes, tokens, and object identity. |
tests/core/test_config_consumers.py |
Covers consumption modes, container categories, and matching. |
src/korvid/k8s/relationship_facts.py |
Uses shared extraction for configuration relationship facts. |
src/korvid/k8s/config_references.py |
Extracts configuration references without literal environment values. |
src/korvid/core/config_propagation.py |
Coordinates metadata and Pod reads into an evidence report. |
src/korvid/core/config_consumers.py |
Projects Pod references into consumer rows by mode. |
docs/superpowers/plans/2026-10-28-config-consumers.md |
Documents implementation steps, constraints, and the core/UI split. |
Review effort: Balanced
5 tasks done
config_references reads the fields that name a configuration object - envFrom, env[].valueFrom, configMap, secret and projected volumes, and imagePullSecrets - and keeps the variable, key, volume and optional flag the propagation view needs, never a value. The relationship graph now builds its USES_CONFIG facts from it, in the same order and with the same field paths, so the graph and the view cannot disagree. Part of #501. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
config_consumers turns a Pod into its references to one object, each with the mode that decides whether a change reaches the container: environment (envFrom, env[].valueFrom), a mounted volume, a subPath or subPathExpr mount, a volume no container mounts, or an image pull secret. Each row names its container and category - container, init container, sidecar (an init container with restartPolicy: Always) or ephemeral - except the Pod-level unmounted and image pull rows. Only references, names and the controlling owner are kept, never a value. Part of #501. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
explain_propagation resolves two sources from the discovery snapshot and reads them together under the run's token: the object's metadata by name, which confirms it exists and which incarnation it is, and the namespace's Pods at the readers' maximum budgets, each projected to its consumers at once. The report keeps both observations, the baseline and the consumers; whether no Pod consumes the object is conclusive only when the Pod list is. A 404 that names the object reports it absent, a 404 that does not is not a deletion, and an unserved source is reported with the token and not read. Part of #501. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The plan for #501 records two departures from the design: P1 lands in two pull requests, this core and the view in #502, and the shared extraction is its own k8s module. It also types a test's malformed volume list for mypy. Part of #501. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The fake reader records each continuation, so the truncated Pod list must ask for each page the server named, and the metadata GET must use the default byte budget: only the Pod list reads at the maxima. Part of #501. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
A spy on read_list asserts the Pod list gets the page size, page cap, deadline and byte budget at the readers' maxima, so a deadline that fell back to the default would fail. Part of #501. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The Secret test now asserts the one GET it makes: secrets, in the namespace, by name, metadata only, at the default byte budget. The plan's privacy constraint lists the identities and reference evidence that leave the run, and what never does. Part of #501. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
hellices
force-pushed
the
feat/501-config-consumers
branch
from
October 28, 2026 23:07
9f1d311 to
6c37b95
Compare
5 tasks done
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.
Closes #501
Summary
The core half of slice P1 of #410: given a ConfigMap or Secret, find every Pod container in its namespace that consumes it, and how, from bounded evidence reads, keeping no configuration value. The view, the shared evidence renderer (#486) and the wiring follow in #502.
k8s/config_references.py: one extraction of the ConfigMap and Secret references a Pod spec makes:envFrom;env[].valueFrom;configMap,secretandprojectedvolumes;imagePullSecrets.It keeps the variable, key, volume and
optionalflag, never a value.Relationship graph: it now builds its
USES_CONFIGfacts from that extraction, in the same order and with the same field paths, so the two cannot disagree. The graph's existing tests pass unchanged.core/config_consumers.py: projects a Pod to its references to one object, by mode:ENV_FROMandENV_KEY;VOLUME, orSUBPATHfor asubPathorsubPathExprmount;UNMOUNTEDfor a volume no container mounts;IMAGE_PULL.Rows name the container and its category (container, init container, sidecar, ephemeral), except the Pod-level
UNMOUNTEDandIMAGE_PULLrows.core/config_propagation.py: the run. It resolves two sources from discovery and reads them together under the run token:Each Pod is projected at once. The report keeps both observations, the baseline and the consumers.
Departures from the design
Both are recorded in the plan:
k8smodule rather than helpers insiderelationship_facts.py, which shrinks from 1,013 to 918 lines.Verification
uv run pytest -p no:tach tests/k8s/test_config_references.py tests/core/test_config_consumers.py tests/core/test_config_propagation.py -q: 32 passed.subPathExprignored;UNMOUNTEDrow;max_pages;max_bytes;consumers_conclusivealways true;expected_uid.uv run pytest -p no:tach tests/k8s/ tests/core/test_relationships*.py tests/ui/test_relationship* -q: 1226 passed (the graph unchanged).check_source_size,ruff check,ruff format --check,mypy,tach check,pytest -n 8): 14796 passed, 39 skipped. One local failure,test_the_measured_release_is_the_installed_one: this machine's venv still has litellm 1.100.3 and cannot install the lock from behind the mirror. CI installs from the lock.Checklist
make checkpasses locally. (Except the litellm version test above, which depends on this machine's venv.)and a fail-closed audit entry, and sensitive reads are still masked.