circle-ir 3.178.0 → 3.179.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -44,6 +44,118 @@ export interface FastjsonPomResolution {
44
44
  * define).
45
45
  */
46
46
  export declare function resolveFastjsonFromPom(pomXml: string): FastjsonPomResolution | null;
47
+ /**
48
+ * Extract the effective Fastjson version from a Gradle build script
49
+ * (`build.gradle` Groovy DSL or `build.gradle.kts` Kotlin DSL).
50
+ *
51
+ * cognium-dev #261 (Gradle-first slice extending #258's pom.xml gate).
52
+ *
53
+ * Recognises three declaration shapes:
54
+ *
55
+ * 1. Direct literal — the classic Groovy / Kotlin single-string form:
56
+ * implementation 'com.alibaba:fastjson:1.2.83_noneautotype'
57
+ * implementation "com.alibaba:fastjson:1.2.83_noneautotype"
58
+ * implementation("com.alibaba:fastjson:1.2.83_noneautotype")
59
+ * Also `api`, `compile`, `runtimeOnly`, `testImplementation`, … — the
60
+ * configuration keyword is not part of the regex; only the
61
+ * `group:artifact:version` triple is matched, so any dependency-
62
+ * configuration prefix works.
63
+ *
64
+ * 2. Groovy interpolation — `implementation "com.alibaba:fastjson:${fastjsonVersion}"`
65
+ * with the property defined via `ext { fastjsonVersion = '1.2.83_noneautotype' }`,
66
+ * `def fastjsonVersion = '1.2.83_noneautotype'`, or top-level `fastjsonVersion = '…'`.
67
+ *
68
+ * 3. Kotlin interpolation — `implementation("com.alibaba:fastjson:$fastjsonVersion")`
69
+ * with the property defined via `val fastjsonVersion = "1.2.83_noneautotype"`
70
+ * or `const val fastjsonVersion = "…"`.
71
+ *
72
+ * Returns `null` on miss (no direct declaration AND no resolvable
73
+ * property reference). The `DeserializationSafetyGatePass` then falls
74
+ * through to its default "do not drop" behaviour on the sink.
75
+ *
76
+ * NOT recognised in this MVP (deferred, follow-ups on #261):
77
+ * - `platform(...)` / `enforcedPlatform(...)` BOM version imports
78
+ * - Version-catalog `libs.versions.toml` references (`libs.fastjson`)
79
+ * - `constraints { }` block versions
80
+ * - `subprojects { }` / `allprojects { }` conditional declarations
81
+ */
82
+ export declare function resolveFastjsonFromGradle(buildGradle: string): FastjsonPomResolution | null;
83
+ /**
84
+ * Result of extracting the effective PyYAML version. `safeByDefault` is
85
+ * true when the parsed version is ≥ 6.0; at that point pyyaml.load()
86
+ * without an explicit `Loader=` keyword argument raises TypeError
87
+ * instead of silently invoking the unsafe default Loader.
88
+ *
89
+ * See https://github.com/yaml/pyyaml/blob/master/CHANGES for the full
90
+ * 6.0 breakage story. The gate consumer must ALSO check the call site
91
+ * for an explicit `Loader=` keyword (fileHasUnsafePyYamlLoader below)
92
+ * — a caller under pyyaml ≥ 6.0 that explicitly passes
93
+ * `Loader=yaml.Loader` or `Loader=yaml.UnsafeLoader` is still
94
+ * dangerous regardless of the version pin.
95
+ */
96
+ export interface PyYamlResolution {
97
+ version: string;
98
+ safeByDefault: boolean;
99
+ }
100
+ /**
101
+ * Extract the effective PyYAML version from a `requirements.txt` file.
102
+ * Recognises the standard PEP 508 shapes (`==`, `>=`, `~=`, `>`,
103
+ * exact pins with trailing modifiers). Package name matched
104
+ * case-insensitively (both `PyYAML` and `pyyaml` are common in the
105
+ * wild).
106
+ *
107
+ * Returns null when no pyyaml line is found or the version string
108
+ * cannot be parsed as `M.m[.p]`. Non-strict on trailing environment
109
+ * markers (` ; python_version >= '3.6'`), which are common on
110
+ * requirements.txt lines.
111
+ */
112
+ export declare function resolvePyYamlFromRequirements(requirementsTxt: string): PyYamlResolution | null;
113
+ /**
114
+ * Extract the effective PyYAML version from a `pyproject.toml`.
115
+ * Recognises the common Poetry and PEP 621 shapes:
116
+ *
117
+ * Poetry — under `[tool.poetry.dependencies]`:
118
+ * PyYAML = "6.0"
119
+ * pyyaml = "^6.0.1"
120
+ * pyyaml = { version = "6.0", extras = ["..."] }
121
+ *
122
+ * PEP 621 — under `[project]` `dependencies` array:
123
+ * dependencies = [ "PyYAML>=6.0", ... ]
124
+ *
125
+ * As with the requirements.txt resolver, non-strict on markers /
126
+ * modifiers; regex-based rather than a full TOML parser to keep the
127
+ * runtime-dep list minimal (Pillar I minimal-dependencies principle).
128
+ */
129
+ export declare function resolvePyYamlFromPyproject(pyprojectToml: string): PyYamlResolution | null;
130
+ /**
131
+ * True when `version` (as `M.m[.p]`) is ≥ 6.0. Handles bare `6`,
132
+ * `6.0`, `6.0.1`, `7`, `10.0`, etc. Returns false on malformed input
133
+ * (defensive — the gate defaults to *do not drop* on missing signal).
134
+ */
135
+ export declare function isPyYamlVersionSafeByDefault(version: string): boolean;
136
+ /**
137
+ * Return true when the file contains an explicit unsafe `Loader=`
138
+ * keyword argument on a `yaml.load(...)` call at or shortly after
139
+ * `sinkLine`. Recognises the well-known unsafe loaders and their
140
+ * qualified forms:
141
+ *
142
+ * Loader=Loader Loader=yaml.Loader
143
+ * Loader=UnsafeLoader Loader=yaml.UnsafeLoader
144
+ * Loader=FullLoader Loader=yaml.FullLoader (technically safer
145
+ * than Loader; still
146
+ * permits arbitrary
147
+ * Python object types)
148
+ *
149
+ * SafeLoader / CSafeLoader / BaseLoader / CBaseLoader are all safe and
150
+ * are NOT matched here.
151
+ *
152
+ * Scans `sinkLine` through the next 9 lines to catch multi-line call
153
+ * shapes; if the closing `)` appears before the window ends the scan
154
+ * stops there. Regex-based (no AST inspection) to stay consistent with
155
+ * the sink-filter-pass conventions and avoid pulling parse state into
156
+ * the gate.
157
+ */
158
+ export declare function fileHasUnsafePyYamlLoader(sourceLines: string[], sinkLine: number): boolean;
47
159
  /**
48
160
  * Return true when the given source text contains an in-file call that
49
161
  * re-enables Fastjson autotype. Even a `_noneautotype` build does not
@@ -1 +1 @@
1
- {"version":3,"file":"dependency-versions.d.ts","sourceRoot":"","sources":["../../src/analysis/dependency-versions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,qBAAqB,GAAG,IAAI,CA8BnF;AAED;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAKrE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAUtE;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAOrE"}
1
+ {"version":3,"file":"dependency-versions.d.ts","sourceRoot":"","sources":["../../src/analysis/dependency-versions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,qBAAqB,GAAG,IAAI,CA8BnF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,qBAAqB,GAAG,IAAI,CAsC3F;AAMD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,6BAA6B,CAC3C,eAAe,EAAE,MAAM,GACtB,gBAAgB,GAAG,IAAI,CAuBzB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,0BAA0B,CACxC,aAAa,EAAE,MAAM,GACpB,gBAAgB,GAAG,IAAI,CAiCzB;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAIrE;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,MAAM,EAAE,EACrB,QAAQ,EAAE,MAAM,GACf,OAAO,CAkBT;AAED;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAKrE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAUtE;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAOrE"}
@@ -65,6 +65,205 @@ export function resolveFastjsonFromPom(pomXml) {
65
65
  }
66
66
  return null;
67
67
  }
68
+ /**
69
+ * Extract the effective Fastjson version from a Gradle build script
70
+ * (`build.gradle` Groovy DSL or `build.gradle.kts` Kotlin DSL).
71
+ *
72
+ * cognium-dev #261 (Gradle-first slice extending #258's pom.xml gate).
73
+ *
74
+ * Recognises three declaration shapes:
75
+ *
76
+ * 1. Direct literal — the classic Groovy / Kotlin single-string form:
77
+ * implementation 'com.alibaba:fastjson:1.2.83_noneautotype'
78
+ * implementation "com.alibaba:fastjson:1.2.83_noneautotype"
79
+ * implementation("com.alibaba:fastjson:1.2.83_noneautotype")
80
+ * Also `api`, `compile`, `runtimeOnly`, `testImplementation`, … — the
81
+ * configuration keyword is not part of the regex; only the
82
+ * `group:artifact:version` triple is matched, so any dependency-
83
+ * configuration prefix works.
84
+ *
85
+ * 2. Groovy interpolation — `implementation "com.alibaba:fastjson:${fastjsonVersion}"`
86
+ * with the property defined via `ext { fastjsonVersion = '1.2.83_noneautotype' }`,
87
+ * `def fastjsonVersion = '1.2.83_noneautotype'`, or top-level `fastjsonVersion = '…'`.
88
+ *
89
+ * 3. Kotlin interpolation — `implementation("com.alibaba:fastjson:$fastjsonVersion")`
90
+ * with the property defined via `val fastjsonVersion = "1.2.83_noneautotype"`
91
+ * or `const val fastjsonVersion = "…"`.
92
+ *
93
+ * Returns `null` on miss (no direct declaration AND no resolvable
94
+ * property reference). The `DeserializationSafetyGatePass` then falls
95
+ * through to its default "do not drop" behaviour on the sink.
96
+ *
97
+ * NOT recognised in this MVP (deferred, follow-ups on #261):
98
+ * - `platform(...)` / `enforcedPlatform(...)` BOM version imports
99
+ * - Version-catalog `libs.versions.toml` references (`libs.fastjson`)
100
+ * - `constraints { }` block versions
101
+ * - `subprojects { }` / `allprojects { }` conditional declarations
102
+ */
103
+ export function resolveFastjsonFromGradle(buildGradle) {
104
+ if (!buildGradle)
105
+ return null;
106
+ // Shape 1 — direct literal declaration. Accepts single-quoted,
107
+ // double-quoted, or paren-wrapped ("Kotlin") forms. The version is
108
+ // any non-quote / non-`$` / non-`)` / non-whitespace run.
109
+ const directRe = /['"(]\s*com\.alibaba:fastjson:([^'"$\s)]+)\s*['")]/;
110
+ const direct = buildGradle.match(directRe);
111
+ if (direct) {
112
+ const version = direct[1];
113
+ return { version, noneAutotype: /_noneautotype/i.test(version) };
114
+ }
115
+ // Shapes 2 + 3 — property reference. Capture the property name (either
116
+ // `${name}` Groovy form or `$name` bare form; Kotlin uses the same
117
+ // string-template syntax as Groovy for this case).
118
+ const propRefRe = /['"(]\s*com\.alibaba:fastjson:\$\{?([A-Za-z_][A-Za-z0-9_]*)\}?\s*['")]/;
119
+ const propRef = buildGradle.match(propRefRe);
120
+ if (!propRef)
121
+ return null;
122
+ const propName = propRef[1];
123
+ // Property definition — accept:
124
+ // `fastjsonVersion = 'X'` (Groovy top-level or ext)
125
+ // `fastjsonVersion = "X"` (Groovy interpolated)
126
+ // `def fastjsonVersion = 'X'` (Groovy local)
127
+ // `val fastjsonVersion = "X"` (Kotlin)
128
+ // `const val fastjsonVersion = "X"` (Kotlin)
129
+ // `fastjsonVersion: 'X'` (Groovy map-syntax, rare)
130
+ // Any leading whitespace / newlines / `=` / `:` before the quote.
131
+ const defRe = new RegExp(`\\b${propName}\\s*[=:]\\s*['"]([^'"\\s]+)['"]`);
132
+ const def = buildGradle.match(defRe);
133
+ if (!def)
134
+ return null;
135
+ const version = def[1];
136
+ return { version, noneAutotype: /_noneautotype/i.test(version) };
137
+ }
138
+ /**
139
+ * Extract the effective PyYAML version from a `requirements.txt` file.
140
+ * Recognises the standard PEP 508 shapes (`==`, `>=`, `~=`, `>`,
141
+ * exact pins with trailing modifiers). Package name matched
142
+ * case-insensitively (both `PyYAML` and `pyyaml` are common in the
143
+ * wild).
144
+ *
145
+ * Returns null when no pyyaml line is found or the version string
146
+ * cannot be parsed as `M.m[.p]`. Non-strict on trailing environment
147
+ * markers (` ; python_version >= '3.6'`), which are common on
148
+ * requirements.txt lines.
149
+ */
150
+ export function resolvePyYamlFromRequirements(requirementsTxt) {
151
+ if (!requirementsTxt)
152
+ return null;
153
+ // Iterate line-by-line so a fatal parse error on one line doesn't
154
+ // sink the whole file. Comment lines and `-r other.txt` includes are
155
+ // ignored (we don't recurse into included files here — the caller
156
+ // controls what manifest string is passed).
157
+ for (const rawLine of requirementsTxt.split(/\r?\n/)) {
158
+ const line = rawLine.replace(/#.*$/, '').trim();
159
+ if (!line)
160
+ continue;
161
+ if (line.startsWith('-'))
162
+ continue;
163
+ // Match: `PyYAML==6.0`, `pyyaml>=6.0.1`, `PyYAML ~= 6.0`,
164
+ // `pyyaml>6`, `PyYAML==6.0 ; python_version>='3.6'`
165
+ const m = line.match(/^(pyyaml)\s*(==|>=|~=|>|===)\s*(\d+(?:\.\d+)*)/i);
166
+ if (!m)
167
+ continue;
168
+ const version = m[3];
169
+ return { version, safeByDefault: isPyYamlVersionSafeByDefault(version) };
170
+ }
171
+ return null;
172
+ }
173
+ /**
174
+ * Extract the effective PyYAML version from a `pyproject.toml`.
175
+ * Recognises the common Poetry and PEP 621 shapes:
176
+ *
177
+ * Poetry — under `[tool.poetry.dependencies]`:
178
+ * PyYAML = "6.0"
179
+ * pyyaml = "^6.0.1"
180
+ * pyyaml = { version = "6.0", extras = ["..."] }
181
+ *
182
+ * PEP 621 — under `[project]` `dependencies` array:
183
+ * dependencies = [ "PyYAML>=6.0", ... ]
184
+ *
185
+ * As with the requirements.txt resolver, non-strict on markers /
186
+ * modifiers; regex-based rather than a full TOML parser to keep the
187
+ * runtime-dep list minimal (Pillar I minimal-dependencies principle).
188
+ */
189
+ export function resolvePyYamlFromPyproject(pyprojectToml) {
190
+ if (!pyprojectToml)
191
+ return null;
192
+ // Poetry key = string form.
193
+ // PyYAML = "6.0" PyYAML = "^6.0" pyyaml = "~=6.0"
194
+ const poetryLine = pyprojectToml.match(/^\s*(pyyaml)\s*=\s*"([\^~=<>]*)(\d+(?:\.\d+)*)"/im);
195
+ if (poetryLine) {
196
+ const version = poetryLine[3];
197
+ return { version, safeByDefault: isPyYamlVersionSafeByDefault(version) };
198
+ }
199
+ // Poetry table form: `pyyaml = { version = "6.0", … }`
200
+ const poetryTable = pyprojectToml.match(/^\s*(pyyaml)\s*=\s*\{[^}]*\bversion\s*=\s*"([\^~=<>]*)(\d+(?:\.\d+)*)"/im);
201
+ if (poetryTable) {
202
+ const version = poetryTable[3];
203
+ return { version, safeByDefault: isPyYamlVersionSafeByDefault(version) };
204
+ }
205
+ // PEP 621 array element: within a `dependencies = [ ... ]` block, a
206
+ // string literal like `"PyYAML>=6.0"` or `"pyyaml==6.0.1"`.
207
+ const pep621 = pyprojectToml.match(/"(pyyaml)\s*(==|>=|~=|>|===)\s*(\d+(?:\.\d+)*)/i);
208
+ if (pep621) {
209
+ const version = pep621[3];
210
+ return { version, safeByDefault: isPyYamlVersionSafeByDefault(version) };
211
+ }
212
+ return null;
213
+ }
214
+ /**
215
+ * True when `version` (as `M.m[.p]`) is ≥ 6.0. Handles bare `6`,
216
+ * `6.0`, `6.0.1`, `7`, `10.0`, etc. Returns false on malformed input
217
+ * (defensive — the gate defaults to *do not drop* on missing signal).
218
+ */
219
+ export function isPyYamlVersionSafeByDefault(version) {
220
+ const parts = version.split('.').map((s) => Number.parseInt(s, 10));
221
+ if (parts.length === 0 || !Number.isFinite(parts[0]))
222
+ return false;
223
+ return parts[0] >= 6;
224
+ }
225
+ /**
226
+ * Return true when the file contains an explicit unsafe `Loader=`
227
+ * keyword argument on a `yaml.load(...)` call at or shortly after
228
+ * `sinkLine`. Recognises the well-known unsafe loaders and their
229
+ * qualified forms:
230
+ *
231
+ * Loader=Loader Loader=yaml.Loader
232
+ * Loader=UnsafeLoader Loader=yaml.UnsafeLoader
233
+ * Loader=FullLoader Loader=yaml.FullLoader (technically safer
234
+ * than Loader; still
235
+ * permits arbitrary
236
+ * Python object types)
237
+ *
238
+ * SafeLoader / CSafeLoader / BaseLoader / CBaseLoader are all safe and
239
+ * are NOT matched here.
240
+ *
241
+ * Scans `sinkLine` through the next 9 lines to catch multi-line call
242
+ * shapes; if the closing `)` appears before the window ends the scan
243
+ * stops there. Regex-based (no AST inspection) to stay consistent with
244
+ * the sink-filter-pass conventions and avoid pulling parse state into
245
+ * the gate.
246
+ */
247
+ export function fileHasUnsafePyYamlLoader(sourceLines, sinkLine) {
248
+ const start = Math.max(0, sinkLine - 1);
249
+ const end = Math.min(sourceLines.length, start + 10);
250
+ const unsafeRe = /\bLoader\s*=\s*(?:yaml\s*\.\s*)?(?:Loader|UnsafeLoader|FullLoader)\b/;
251
+ for (let i = start; i < end; i++) {
252
+ const ln = sourceLines[i] ?? '';
253
+ if (unsafeRe.test(ln))
254
+ return true;
255
+ // Stop once the call closes — the `)` at the top-level. Fine
256
+ // approximation: any bare `)` at the START of a stripped line, or
257
+ // trailing `)` at end of a stripped line, signals close.
258
+ const stripped = ln.trim();
259
+ if (i > start && (stripped === ')' || stripped.endsWith(')'))) {
260
+ // Also test the current line before we stop, in case Loader= is
261
+ // on the same line as the closing paren.
262
+ return false;
263
+ }
264
+ }
265
+ return false;
266
+ }
68
267
  /**
69
268
  * Return true when the given source text contains an in-file call that
70
269
  * re-enables Fastjson autotype. Even a `_noneautotype` build does not
@@ -1 +1 @@
1
- {"version":3,"file":"dependency-versions.js","sourceRoot":"","sources":["../../src/analysis/dependency-versions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAcH;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAc;IACnD,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEzB,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC1F,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAC7B,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;IACnE,CAAC;IAED,8DAA8D;IAC9D,mEAAmE;IACnE,kEAAkE;IAClE,oCAAoC;IACpC,MAAM,KAAK,GAAG,qCAAqC,CAAC;IACpD,IAAI,CAAyB,CAAC;IAC9B,OAAO,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACnB,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,qCAAqC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACpE,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,2CAA2C,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC1E,IAAI,GAAG,KAAK,aAAa;YAAE,SAAS;QACpC,IAAI,GAAG,KAAK,UAAU,IAAI,GAAG,KAAK,WAAW;YAAE,SAAS;QACxD,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,qCAAqC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACpE,IAAI,CAAC,GAAG;YAAE,SAAS;QACnB,+DAA+D;QAC/D,2DAA2D;QAC3D,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACnC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IACpE,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,6BAA6B,CAAC,MAAc;IAC1D,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,4DAA4D;IAC5D,+DAA+D;IAC/D,OAAO,oCAAoC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC3D,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,8BAA8B,CAAC,MAAc;IAC3D,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,IAAI,4BAA4B,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3D,IAAI,8BAA8B,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7D,6EAA6E;IAC7E,oEAAoE;IACpE,6DAA6D;IAC7D,2DAA2D;IAC3D,IAAI,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAChD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,6BAA6B,CAAC,MAAc;IAC1D,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,IAAI,8BAA8B,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7D,gFAAgF;IAChF,4DAA4D;IAC5D,IAAI,6BAA6B,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5D,OAAO,KAAK,CAAC;AACf,CAAC"}
1
+ {"version":3,"file":"dependency-versions.js","sourceRoot":"","sources":["../../src/analysis/dependency-versions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAcH;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAc;IACnD,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAEzB,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAC;IAC1F,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAC7B,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;IACnE,CAAC;IAED,8DAA8D;IAC9D,mEAAmE;IACnE,kEAAkE;IAClE,oCAAoC;IACpC,MAAM,KAAK,GAAG,qCAAqC,CAAC;IACpD,IAAI,CAAyB,CAAC;IAC9B,OAAO,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACnB,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,qCAAqC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACpE,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,2CAA2C,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC1E,IAAI,GAAG,KAAK,aAAa;YAAE,SAAS;QACpC,IAAI,GAAG,KAAK,UAAU,IAAI,GAAG,KAAK,WAAW;YAAE,SAAS;QACxD,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,CAAC,qCAAqC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACpE,IAAI,CAAC,GAAG;YAAE,SAAS;QACnB,+DAA+D;QAC/D,2DAA2D;QAC3D,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACnC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IACpE,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,UAAU,yBAAyB,CAAC,WAAmB;IAC3D,IAAI,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAE9B,+DAA+D;IAC/D,mEAAmE;IACnE,0DAA0D;IAC1D,MAAM,QAAQ,GAAG,oDAAoD,CAAC;IACtE,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QAC1B,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;IACnE,CAAC;IAED,uEAAuE;IACvE,mEAAmE;IACnE,mDAAmD;IACnD,MAAM,SAAS,GACb,wEAAwE,CAAC;IAC3E,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC7C,IAAI,CAAC,OAAO;QAAE,OAAO,IAAI,CAAC;IAE1B,MAAM,QAAQ,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAC5B,gCAAgC;IAChC,qEAAqE;IACrE,iEAAiE;IACjE,0DAA0D;IAC1D,oDAAoD;IACpD,oDAAoD;IACpD,qEAAqE;IACrE,kEAAkE;IAClE,MAAM,KAAK,GAAG,IAAI,MAAM,CACtB,MAAM,QAAQ,iCAAiC,CAChD,CAAC;IACF,MAAM,GAAG,GAAG,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACrC,IAAI,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IAEtB,MAAM,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IACvB,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;AACnE,CAAC;AAwBD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,6BAA6B,CAC3C,eAAuB;IAEvB,IAAI,CAAC,eAAe;QAAE,OAAO,IAAI,CAAC;IAElC,kEAAkE;IAClE,qEAAqE;IACrE,kEAAkE;IAClE,4CAA4C;IAC5C,KAAK,MAAM,OAAO,IAAI,eAAe,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACrD,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAChD,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QAEnC,0DAA0D;QAC1D,oDAAoD;QACpD,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAClB,iDAAiD,CAClD,CAAC;QACF,IAAI,CAAC,CAAC;YAAE,SAAS;QACjB,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACrB,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,4BAA4B,CAAC,OAAO,CAAC,EAAE,CAAC;IAC3E,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,0BAA0B,CACxC,aAAqB;IAErB,IAAI,CAAC,aAAa;QAAE,OAAO,IAAI,CAAC;IAEhC,4BAA4B;IAC5B,4DAA4D;IAC5D,MAAM,UAAU,GAAG,aAAa,CAAC,KAAK,CACpC,mDAAmD,CACpD,CAAC;IACF,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;QAC9B,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,4BAA4B,CAAC,OAAO,CAAC,EAAE,CAAC;IAC3E,CAAC;IAED,uDAAuD;IACvD,MAAM,WAAW,GAAG,aAAa,CAAC,KAAK,CACrC,0EAA0E,CAC3E,CAAC;IACF,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;QAC/B,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,4BAA4B,CAAC,OAAO,CAAC,EAAE,CAAC;IAC3E,CAAC;IAED,oEAAoE;IACpE,4DAA4D;IAC5D,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,CAChC,iDAAiD,CAClD,CAAC;IACF,IAAI,MAAM,EAAE,CAAC;QACX,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QAC1B,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,4BAA4B,CAAC,OAAO,CAAC,EAAE,CAAC;IAC3E,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,4BAA4B,CAAC,OAAe;IAC1D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IACpE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACnE,OAAO,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACvB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,yBAAyB,CACvC,WAAqB,EACrB,QAAgB;IAEhB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,EAAE,KAAK,GAAG,EAAE,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,sEAAsE,CAAC;IACxF,KAAK,IAAI,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QACjC,MAAM,EAAE,GAAG,WAAW,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAChC,IAAI,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,OAAO,IAAI,CAAC;QACnC,6DAA6D;QAC7D,kEAAkE;QAClE,yDAAyD;QACzD,MAAM,QAAQ,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC;QAC3B,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC,QAAQ,KAAK,GAAG,IAAI,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YAC9D,gEAAgE;YAChE,yCAAyC;YACzC,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,6BAA6B,CAAC,MAAc;IAC1D,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,4DAA4D;IAC5D,+DAA+D;IAC/D,OAAO,oCAAoC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAC3D,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,8BAA8B,CAAC,MAAc;IAC3D,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,IAAI,4BAA4B,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3D,IAAI,8BAA8B,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7D,6EAA6E;IAC7E,oEAAoE;IACpE,6DAA6D;IAC7D,2DAA2D;IAC3D,IAAI,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAChD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,6BAA6B,CAAC,MAAc;IAC1D,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,IAAI,8BAA8B,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7D,gFAAgF;IAChF,4DAA4D;IAC5D,IAAI,6BAA6B,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IAC5D,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -47,6 +47,8 @@ export interface DeserializationSafetyGateResult {
47
47
  droppedJackson: number;
48
48
  /** Sinks dropped by Gate C (SnakeYAML SafeConstructor). */
49
49
  droppedSnakeYaml: number;
50
+ /** Sinks dropped by Gate D (Python PyYAML ≥ 6.0 default-safe). */
51
+ droppedPyYaml: number;
50
52
  }
51
53
  export declare class DeserializationSafetyGatePass implements AnalysisPass<DeserializationSafetyGateResult> {
52
54
  private readonly dependencyContext?;
@@ -1 +1 @@
1
- {"version":3,"file":"deserialization-safety-gate-pass.d.ts","sourceRoot":"","sources":["../../../src/analysis/passes/deserialization-safety-gate-pass.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAG9E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAQ3D,MAAM,WAAW,+BAA+B;IAC9C,uDAAuD;IACvD,eAAe,EAAE,MAAM,CAAC;IACxB,kEAAkE;IAClE,cAAc,EAAE,MAAM,CAAC;IACvB,2DAA2D;IAC3D,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAWD,qBAAa,6BACX,YAAW,YAAY,CAAC,+BAA+B,CAAC;IAK5C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC;IAH/C,QAAQ,CAAC,IAAI,iCAAiC;IAC9C,QAAQ,CAAC,QAAQ,EAAG,UAAU,CAAU;gBAEX,iBAAiB,CAAC,EAAE,iBAAiB,YAAA;IAElE,GAAG,CAAC,GAAG,EAAE,WAAW,GAAG,+BAA+B;CAoFvD"}
1
+ {"version":3,"file":"deserialization-safety-gate-pass.d.ts","sourceRoot":"","sources":["../../../src/analysis/passes/deserialization-safety-gate-pass.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAG9E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAY3D,MAAM,WAAW,+BAA+B;IAC9C,uDAAuD;IACvD,eAAe,EAAE,MAAM,CAAC;IACxB,kEAAkE;IAClE,cAAc,EAAE,MAAM,CAAC;IACvB,2DAA2D;IAC3D,gBAAgB,EAAE,MAAM,CAAC;IACzB,kEAAkE;IAClE,aAAa,EAAE,MAAM,CAAC;CACvB;AAeD,qBAAa,6BACX,YAAW,YAAY,CAAC,+BAA+B,CAAC;IAK5C,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC;IAH/C,QAAQ,CAAC,IAAI,iCAAiC;IAC9C,QAAQ,CAAC,QAAQ,EAAG,UAAU,CAAU;gBAEX,iBAAiB,CAAC,EAAE,iBAAiB,YAAA;IAElE,GAAG,CAAC,GAAG,EAAE,WAAW,GAAG,+BAA+B;CAiIvD"}
@@ -38,13 +38,16 @@
38
38
  *
39
39
  * See `docs/PASSES.md` for the canonical pass registry entry.
40
40
  */
41
- import { resolveFastjsonFromPom, fileReenablesFastjsonAutotype, fileEnablesJacksonPolymorphism, fileConfiguresSnakeYamlSafely, } from '../dependency-versions.js';
41
+ import { resolveFastjsonFromPom, resolveFastjsonFromGradle, resolvePyYamlFromRequirements, resolvePyYamlFromPyproject, fileHasUnsafePyYamlLoader, fileReenablesFastjsonAutotype, fileEnablesJacksonPolymorphism, fileConfiguresSnakeYamlSafely, } from '../dependency-versions.js';
42
42
  const FASTJSON_METHODS = new Set(['parseObject', 'parse']);
43
43
  const FASTJSON_CLASSES = new Set(['JSON', 'JSONObject']);
44
44
  const JACKSON_METHODS = new Set(['readValue', 'convertValue', 'treeToValue']);
45
45
  const JACKSON_CLASSES = new Set(['ObjectMapper', 'ObjectReader']);
46
46
  const SNAKEYAML_METHODS = new Set(['load', 'loadAs', 'loadAll']);
47
47
  const SNAKEYAML_CLASSES = new Set(['Yaml']);
48
+ // Python PyYAML gate (Gate D — cognium-dev #261 Python slice).
49
+ const PYYAML_METHODS = new Set(['load']);
50
+ const PYYAML_CLASSES = new Set(['yaml']);
48
51
  export class DeserializationSafetyGatePass {
49
52
  dependencyContext;
50
53
  name = 'deserialization-safety-gate';
@@ -54,11 +57,11 @@ export class DeserializationSafetyGatePass {
54
57
  }
55
58
  run(ctx) {
56
59
  const { graph, language, code } = ctx;
57
- // Java-only for the MVP. Other languages (Python pyyaml, JS
58
- // Deserialize, Rust bincode) can extend the gate on their own
59
- // manifests in follow-up scopes.
60
- if (language !== 'java') {
61
- return { droppedFastjson: 0, droppedJackson: 0, droppedSnakeYaml: 0 };
60
+ // Java + Python for the MVP. Other languages (JS Deserialize,
61
+ // Rust bincode) can extend the gate on their own manifests in
62
+ // follow-up scopes.
63
+ if (language !== 'java' && language !== 'python') {
64
+ return { droppedFastjson: 0, droppedJackson: 0, droppedSnakeYaml: 0, droppedPyYaml: 0 };
62
65
  }
63
66
  // Same sink-source discovery as SinkSemanticsPass: prefer
64
67
  // SinkFilterResult when the real pipeline has run, otherwise fall
@@ -68,17 +71,44 @@ export class DeserializationSafetyGatePass {
68
71
  ? ctx.getResult('sink-filter').sinks
69
72
  : graph.ir.taint.sinks;
70
73
  // --- Gate A: Fastjson _noneautotype ------------------------------------
74
+ // Consult pom.xml first; fall back to build.gradle when pom does
75
+ // not resolve. Both manifests may be supplied by a caller that
76
+ // scans a multi-build project; either one indicating the hardened
77
+ // classifier is sufficient to drop the sink.
71
78
  const pomXml = this.dependencyContext?.java?.pomXml;
72
- const fastjson = pomXml ? resolveFastjsonFromPom(pomXml) : null;
79
+ const buildGradle = this.dependencyContext?.java?.buildGradle;
80
+ const fastjson = (pomXml ? resolveFastjsonFromPom(pomXml) : null) ??
81
+ (buildGradle ? resolveFastjsonFromGradle(buildGradle) : null);
73
82
  const fastjsonHardened = fastjson?.noneAutotype === true &&
74
83
  !fileReenablesFastjsonAutotype(code);
75
84
  // --- Gate B: Jackson polymorphism ---------------------------------------
76
85
  const jacksonSafe = !fileEnablesJacksonPolymorphism(code);
77
86
  // --- Gate C: SnakeYAML SafeConstructor ----------------------------------
78
87
  const snakeYamlSafe = fileConfiguresSnakeYamlSafely(code);
88
+ // --- Gate D: PyYAML ≥ 6.0 (Python) --------------------------------------
89
+ // Under pyyaml ≥ 6.0, `yaml.load(x)` without an explicit `Loader=`
90
+ // keyword arg raises TypeError (safe-by-default); callers that pass
91
+ // `Loader=SafeLoader` are safe; callers that pass an unsafe Loader
92
+ // (`Loader=Loader` / `UnsafeLoader` / `FullLoader`) are still
93
+ // dangerous regardless of the version pin — those need per-call
94
+ // inspection to preserve.
95
+ const requirementsTxt = this.dependencyContext?.python?.requirementsTxt;
96
+ const pyprojectToml = this.dependencyContext?.python?.pyprojectToml;
97
+ const pyYaml = (requirementsTxt ? resolvePyYamlFromRequirements(requirementsTxt) : null) ??
98
+ (pyprojectToml ? resolvePyYamlFromPyproject(pyprojectToml) : null);
99
+ const pyYamlSafeByDefault = pyYaml?.safeByDefault === true;
100
+ // Lazy: only split source lines when we actually need per-call
101
+ // inspection (i.e. gate D is active and could fire).
102
+ let sourceLines = null;
103
+ const getSourceLines = () => {
104
+ if (sourceLines === null)
105
+ sourceLines = code.split('\n');
106
+ return sourceLines;
107
+ };
79
108
  let droppedFastjson = 0;
80
109
  let droppedJackson = 0;
81
110
  let droppedSnakeYaml = 0;
111
+ let droppedPyYaml = 0;
82
112
  const kept = sinks.filter((sink) => {
83
113
  if (sink.type !== 'deserialization')
84
114
  return true;
@@ -107,16 +137,29 @@ export class DeserializationSafetyGatePass {
107
137
  droppedSnakeYaml++;
108
138
  return false;
109
139
  }
140
+ // Gate D — PyYAML (Python). `sink.class` may be `undefined` for
141
+ // Python: unlike Java, Python calls do not carry receiver-type
142
+ // resolution into the CallInfo, so the taint-matcher's sinkMap
143
+ // assigns undefined for the class field. Accept undefined OR
144
+ // exact-`'yaml'` (mirrors Gate A's Fastjson check).
145
+ if (language === 'python' &&
146
+ pyYamlSafeByDefault &&
147
+ PYYAML_METHODS.has(sink.method) &&
148
+ (sink.class === undefined || PYYAML_CLASSES.has(sink.class)) &&
149
+ !fileHasUnsafePyYamlLoader(getSourceLines(), sink.line)) {
150
+ droppedPyYaml++;
151
+ return false;
152
+ }
110
153
  return true;
111
154
  });
112
- const totalDropped = droppedFastjson + droppedJackson + droppedSnakeYaml;
155
+ const totalDropped = droppedFastjson + droppedJackson + droppedSnakeYaml + droppedPyYaml;
113
156
  if (totalDropped > 0) {
114
157
  // Mutate in place so downstream passes see the reduced sink set.
115
158
  // Matches SinkSemanticsPass's contract.
116
159
  sinks.length = 0;
117
160
  sinks.push(...kept);
118
161
  }
119
- return { droppedFastjson, droppedJackson, droppedSnakeYaml };
162
+ return { droppedFastjson, droppedJackson, droppedSnakeYaml, droppedPyYaml };
120
163
  }
121
164
  }
122
165
  //# sourceMappingURL=deserialization-safety-gate-pass.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"deserialization-safety-gate-pass.js","sourceRoot":"","sources":["../../../src/analysis/passes/deserialization-safety-gate-pass.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"deserialization-safety-gate-pass.js","sourceRoot":"","sources":["../../../src/analysis/passes/deserialization-safety-gate-pass.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"taint-matcher.d.ts","sourceRoot":"","sources":["../../src/analysis/taint-matcher.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAgB,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAkB,KAAK,EAAwB,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAClK,OAAO,KAAK,EAAE,WAAW,EAAiB,WAAW,EAAoB,MAAM,oBAAoB,CAAC;AACpG,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAgC7E;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,QAAQ,EAAE,EACjB,KAAK,EAAE,QAAQ,EAAE,EACjB,MAAM,GAAE,WAAgC,EACxC,aAAa,CAAC,EAAE,qBAAqB,EACrC,QAAQ,CAAC,EAAE,iBAAiB,EAC5B,IAAI,CAAC,EAAE,MAAM,GACZ,KAAK,CASP;AAqID;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,WAAW,EAAE,EACtB,KAAK,EAAE,SAAS,EAAE,EAClB,IAAI,EAAE,MAAM,GACX,IAAI,CAYN;AA02ED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,WAAW,GACnB,OAAO,CAET"}
1
+ {"version":3,"file":"taint-matcher.d.ts","sourceRoot":"","sources":["../../src/analysis/taint-matcher.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAgB,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAkB,KAAK,EAAwB,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAClK,OAAO,KAAK,EAAE,WAAW,EAAiB,WAAW,EAAoB,MAAM,oBAAoB,CAAC;AACpG,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAgC7E;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,QAAQ,EAAE,EACjB,KAAK,EAAE,QAAQ,EAAE,EACjB,MAAM,GAAE,WAAgC,EACxC,aAAa,CAAC,EAAE,qBAAqB,EACrC,QAAQ,CAAC,EAAE,iBAAiB,EAC5B,IAAI,CAAC,EAAE,MAAM,GACZ,KAAK,CASP;AAqID;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,WAAW,EAAE,EACtB,KAAK,EAAE,SAAS,EAAE,EAClB,IAAI,EAAE,MAAM,GACX,IAAI,CAYN;AA43ED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,WAAW,GACnB,OAAO,CAET"}
@@ -2407,6 +2407,24 @@ function calculateSinkConfidence(call, pattern) {
2407
2407
  if (pattern.class && call.receiver) {
2408
2408
  if (receiverMightBeClass(call.receiver, pattern.class)) {
2409
2409
  confidence += 0.1;
2410
+ // cognium-dev #260 — EXACT-match tiebreaker. When two patterns
2411
+ // for the same `(method, cwe)` both accept the receiver — one
2412
+ // exactly (e.g. class: 'Ctx' vs receiver 'Ctx') and one via
2413
+ // `receiverMightBeClass` fuzzy heuristics (e.g. class: 'Context'
2414
+ // vs receiver 'Ctx' via the includes/40%-length rule at
2415
+ // taint-matcher.ts:2366) — the fuzzy match used to win the
2416
+ // `sinkMap` dedup slot when it iterated first (both had the same
2417
+ // 0.9 confidence). The extra boost here guarantees the exact-
2418
+ // match pattern's `arg_positions` are the ones emitted on the
2419
+ // final sink. Fixes the fiber `c.Redirect(next)` shape whose
2420
+ // sink was emitted with the gin `class: 'Context'` pattern's
2421
+ // `arg_positions: [1]` instead of fiber `class: 'Ctx'`'s
2422
+ // `arg_positions: [0]`, dropping the taint flow silently.
2423
+ const receiverLc = call.receiver.toLowerCase();
2424
+ const classLc = pattern.class.toLowerCase();
2425
+ if (call.receiver === pattern.class || receiverLc === classLc) {
2426
+ confidence += 0.05;
2427
+ }
2410
2428
  }
2411
2429
  }
2412
2430
  // Higher confidence for critical severity patterns