Skip to content

Commit b3fdc92

Browse files
committed
fix(k8s): restore Resource label so the K8s pipeline produces nodes + INFRA_MAPS
An earlier relabel (extract_k8s.c Resource->Class, to satisfy labels-valid) left pass_k8s.c filtering on label=='Resource' (line 391) — so it skipped every K8s def and produced ZERO Resource nodes and ZERO INFRA_MAPS edges (7 make-test failures + the consequent LeakSanitizer leak from those tests early-returning). Fix the whole chain accurately: add 'Resource' to inv_label_valid (the def-label allowlist), revert extract_k8s.c to emit 'Resource' (manifest + kustomize), so pass_k8s.c matches -> Resource nodes + INFRA_MAPS restored. K8s repro goldens updated Class->Resource to match. Also guard 3 vendored scanners' zero-length memcpy (crystal/rescript/purescript) against UBSan NULL-nonnull (documented in vendored MANIFEST.md). Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
1 parent aff9bfb commit b3fdc92

7 files changed

Lines changed: 35 additions & 20 deletions

File tree

internal/cbm/extract_k8s.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ static void emit_kustomize_kind_def(CBMExtractCtx *ctx, TSNode mapping) {
179179
CBMDefinition def = {0};
180180
def.name = cbm_arena_strdup(a, kind);
181181
def.qualified_name = cbm_arena_sprintf(a, "%s.%s", ctx->module_qn, kind);
182-
def.label = cbm_arena_strdup(a, "Class");
182+
def.label = cbm_arena_strdup(a, "Resource");
183183
def.file_path = ctx->rel_path;
184184
def.start_line = ts_node_start_point(mapping).row + TS_LINE_OFFSET;
185185
def.end_line = ts_node_end_point(mapping).row + TS_LINE_OFFSET;
@@ -334,10 +334,10 @@ static void extract_k8s_manifest(CBMExtractCtx *ctx) {
334334
CBMDefinition def = {0};
335335
def.name = cbm_arena_strdup(a, def_name);
336336
def.qualified_name = cbm_arena_sprintf(a, "%s.%s", ctx->module_qn, def_name);
337-
// "Class" is the canonical def label for a K8s resource kind: "Resource"
338-
// is not in the graph's known label set, so a resource def carrying it is
339-
// dropped by downstream label validation.
340-
def.label = cbm_arena_strdup(a, "Class");
337+
// "Resource" is the canonical def label for a K8s resource kind. It is a
338+
// valid graph label and is what the K8s pipeline pass (pass_k8s.c) filters
339+
// on to upsert Resource nodes and emit INFRA_MAPS edges.
340+
def.label = cbm_arena_strdup(a, "Resource");
341341
def.file_path = ctx->rel_path;
342342
def.start_line = ts_node_start_point(mapping).row + TS_LINE_OFFSET;
343343
def.end_line = ts_node_end_point(mapping).row + TS_LINE_OFFSET;

internal/cbm/vendored/grammars/MANIFEST.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,18 @@ Guarded by the `contract_all_grammars_in_graph` graph-breadth test in
5050
| slang | added to the C-family declarator-name gate (tree-sitter-cpp/hlsl fork) |
5151
| squirrel | `resolve_func_name`: `function_declaration``identifier` child |
5252

53+
## Local source patches (applied atop pinned upstream)
54+
55+
The grammars below carry a small local patch to their vendored `scanner.c`, on
56+
top of the pinned upstream commit recorded in the vendoring table below.
57+
Re-vendoring from upstream must re-apply these.
58+
59+
| grammar | location | patch | reason |
60+
|---|---|---|---|
61+
| crystal | `crystal/scanner.c`, serialize | guard `memcpy(&buffer[offset], state->literals.contents, literal_content_size)` with `if (literal_content_size > 0)` | UBSan: zero-length `memcpy` with a NULL/0-size source on the empty-state serialize round-trip (formal UB, harmless) |
62+
| rescript | `rescript/scanner.c`, deserialize | guard `memcpy(state, buffer, n_bytes)` with `if (n_bytes > 0)` | UBSan: zero-length `memcpy` with a NULL `buffer` / `n_bytes == 0` on empty-state deserialize (formal UB, harmless). The sibling serialize copies a fixed `sizeof(ScannerState)` (always > 0, non-NULL src) and needs no guard. |
63+
| purescript | `purescript/scanner.c`, serialize | guard `memcpy(buffer, indents->data, to_copy)` with `if (to_copy > 0)` | UBSan: zero-length `memcpy` with a NULL/0-size source when the indent vector is empty (formal UB, harmless) |
64+
5365
## Vendored from verified upstream
5466

5567
| grammar | cur ABI | upstream repo | pinned commit | verdict | LICENSE |

internal/cbm/vendored/grammars/crystal/scanner.c

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/cbm/vendored/grammars/purescript/scanner.c

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/cbm/vendored/grammars/rescript/scanner.c

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/repro/repro_grammar_build.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@
7272
* STRUCTURAL WITH DEFS (dims 1-5 + R):
7373
* DOCKERFILE -- var_types = {env_instruction, arg_instruction} -> "Variable".
7474
* GOMOD -- var_types = {require_directive, replace_directive} -> "Variable".
75-
* K8S -- semantic extractor (cbm_extract_k8s); extracts kind -> "Class".
76-
* KUSTOMIZE -- semantic extractor (cbm_extract_k8s); extracts kind -> "Class".
75+
* K8S -- semantic extractor (cbm_extract_k8s); extracts kind -> "Resource".
76+
* KUSTOMIZE -- semantic extractor (cbm_extract_k8s); extracts kind -> "Resource".
7777
*
7878
* CALLABLE (dims 1-6 + R, no pipeline):
7979
* GN -- call_types = {call_expression}; no func_types -> no Function def.
@@ -656,12 +656,12 @@ TEST(repro_grammar_build_just) {
656656
* Idiomatic Kubernetes manifest with a Deployment (apiVersion: apps/v1,
657657
* kind: Deployment). The K8s/Kustomize semantic extractor cbm_extract_k8s()
658658
* is called for CBM_LANG_K8S; it reads the kind field from the YAML tree and
659-
* maps it to a def with label "Class" and qualified_name based on the kind.
659+
* maps it to a def with label "Resource" and qualified_name based on the kind.
660660
* The grammar itself reuses yaml grammar + yaml_var_types; the semantic layer
661-
* adds the kind-based "Class" def.
661+
* adds the kind-based "Resource" def.
662662
*
663-
* Dims asserted: 1-5 + R ("Class" for the Deployment kind).
664-
* Dim 5 expected GREEN: "Class" def extracted by cbm_extract_k8s for the kind.
663+
* Dims asserted: 1-5 + R ("Resource" for the Deployment kind).
664+
* Dim 5 expected GREEN: "Resource" def extracted by cbm_extract_k8s for the kind.
665665
* RED documents that the K8s semantic extractor is not minting the kind def.
666666
* Dims 6-8 SKIPPED: no call_types in the K8s spec; no pipeline.
667667
* Expected GREEN: dims 1-5. Robustness should pass.
@@ -695,19 +695,19 @@ TEST(repro_grammar_build_k8s) {
695695
" value: info\n";
696696
static const char bad[] = "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n name:";
697697
if (build_struct_battery("K8s", src, CBM_LANG_K8S, "deployment.yaml",
698-
"Class", NULL) != 0)
698+
"Resource", NULL) != 0)
699699
return 1;
700700
return build_robustness("K8s", bad, CBM_LANG_K8S, "deployment.yaml");
701701
}
702702

703703
/* ── Kustomize ────────────────────────────────────────────────────────────────
704704
* Idiomatic kustomization.yaml: the Kustomize overlay tool's root file
705705
* (kind: Kustomization). cbm_extract_k8s() is called for CBM_LANG_KUSTOMIZE
706-
* just as for CBM_LANG_K8S; it should mint a "Class" def for the
706+
* just as for CBM_LANG_K8S; it should mint a "Resource" def for the
707707
* "Kustomization" kind, which is the canonical Kustomize resource kind.
708708
*
709-
* Dims asserted: 1-5 + R ("Class" for the Kustomization kind).
710-
* Dim 5 expected GREEN: "Class" def for "Kustomization" from cbm_extract_k8s.
709+
* Dims asserted: 1-5 + R ("Resource" for the Kustomization kind).
710+
* Dim 5 expected GREEN: "Resource" def for "Kustomization" from cbm_extract_k8s.
711711
* RED documents that the Kustomize path in the semantic extractor is broken.
712712
* Dims 6-8 SKIPPED: no call_types in the Kustomize spec; no pipeline.
713713
* Expected GREEN: dims 1-5. Robustness should pass.
@@ -738,7 +738,7 @@ TEST(repro_grammar_build_kustomize) {
738738
" - PORT=8080\n";
739739
static const char bad[] = "apiVersion: kustomize.config.k8s.io/v1beta1\nkind: Kustomization\nresources:";
740740
if (build_struct_battery("Kustomize", src, CBM_LANG_KUSTOMIZE,
741-
"kustomization.yaml", "Class", NULL) != 0)
741+
"kustomization.yaml", "Resource", NULL) != 0)
742742
return 1;
743743
return build_robustness("Kustomize", bad, CBM_LANG_KUSTOMIZE,
744744
"kustomization.yaml");

tests/repro/repro_invariant_lib.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ static inline int inv_label_valid(const char *label) {
4242
"Function", "Method", "Class", "Interface", "Struct", "Enum", "EnumMember",
4343
"Module", "Variable", "Constant", "Field", "Trait", "Type", "TypeAlias",
4444
"Namespace", "Property", "Route", "Macro", "Union", "Protocol","Mixin",
45-
"Package", "Object", "Section", "Impl", "Annotation", NULL};
45+
"Package", "Object", "Section", "Impl", "Annotation", "Resource", NULL};
4646
if (!label)
4747
return 0;
4848
for (const char **v = valid; *v; v++)

0 commit comments

Comments
 (0)