Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 93 additions & 2 deletions spec/audit.py
Original file line number Diff line number Diff line change
Expand Up @@ -1468,14 +1468,50 @@ def split_jobs(text):
return blocks


# A `key: |`/`key: >` block-scalar indicator, with an optional anchor (`&name`) before it.
# Anchored whole-line so `key: "a|b"` does not match.
_BLOCK_SCALAR_KEY = re.compile(r"^[^:#\n]*:\s*(&\S+\s+)?[|>][0-9+-]*\s*(#.*)?$")
# A bare `- |`/`- >` sequence item, a block scalar with no mapping key at all (a matrix string).
_BARE_BLOCK_SCALAR = re.compile(r"^(&\S+\s+)?[|>][0-9+-]*\s*(#.*)?$")
# A step's `- key: |` sequence-item prefix, stripped before matching the two patterns above.
_SEQUENCE_ITEM_PREFIX = re.compile(r"^-[ \t]+")


def _code_view(text):
"""Workflow text with comment-only lines dropped, so a token mentioned only in a comment is not signal.
"""Workflow text with comment-only lines and block-scalar bodies dropped, neither is structure.

A carried task file documents its own contract in comments (build-release-task.yml names
`release-asset-` and `artifact-ids:` in prose), so a raw substring search over the whole text would
both false-pass a missing handoff and false-flag a forbidden token that appears only in a comment.
A block-scalar string value (`name: |` followed by indented text) can hide or fake a token the same
way, so its body is dropped too, keeping only the `key:` line itself (ptr727/ProjectTemplate#949).
"""
return "\n".join(ln for ln in text.splitlines() if not ln.lstrip().startswith("#"))
out = []
skip_indent = None
for ln in text.splitlines():
if ln.lstrip().startswith("#"):
continue
if skip_indent is not None:
if ln.strip() and (len(ln) - len(ln.lstrip())) <= skip_indent:
skip_indent = None # a dedent back to (or past) the key column ends the block body
Comment thread
qodo-code-review[bot] marked this conversation as resolved.
else:
continue # still inside the block scalar body, not real structure
stripped = ln.lstrip()
dash_col = len(ln) - len(stripped)
key_col = dash_col
dash = _SEQUENCE_ITEM_PREFIX.match(stripped)
if dash:
# A keyed scalar's boundary is the key's own column, not the dash's.
# A sibling key genuinely at that column (`env:` alongside a `- run: |` step) is real structure.
key_col += dash.end()
stripped = stripped[dash.end() :]
if _BLOCK_SCALAR_KEY.match(stripped):
skip_indent = key_col
Comment thread
qodo-code-review[bot] marked this conversation as resolved.
elif dash and _BARE_BLOCK_SCALAR.match(stripped):
# A bare `- |` has no key, so its own boundary is the dash's column, not a key past it.
skip_indent = dash_col
out.append(ln)
return "\n".join(out)


def job_level_names(blocks):
Expand Down Expand Up @@ -2777,6 +2813,16 @@ def _selftest():
deploy_contract,
1,
),
(
# A block scalar crafted to contain the required token as string content must still report it missing.
# The real `with:` mapping is removed here, so only the block scalar carries the text (ptr727/ProjectTemplate#949).
"deploy-site.yml caller stub with the with:/environment: tokens only inside a block-scalar name still reports missing",
deploy_stub.replace(
" name: Deploy job\n", " name: |\n with:\n environment:\n"
).replace(" with:\n environment: ${{ inputs.environment }}\n", ""),
deploy_contract,
1,
),
]
# The stage-5 type-specific hub tasks carry no manifest entry yet, since no repo has adopted a caller stub for them.
# These fixtures exercise the contract adoption will register, proving the interface engine reads it correctly before any downstream repo depends on that reading.
Expand Down Expand Up @@ -2893,6 +2939,51 @@ def _selftest():
else:
print(" ok split_jobs (inline-mapping job captured with its content)")

# _code_view()'s block-scalar handling: only the body is dropped, never the key line itself.
code_view_cases = [
(
"block scalar body dropped, key line kept",
" deploy:\n name: |\n with:\n environment:\n",
" deploy:\n name: |",
),
(
"a dedented sibling key ends the block scalar body",
" deploy:\n name: |\n with:\n with:\n environment: prod\n",
" deploy:\n name: |\n with:\n environment: prod",
),
(
"folded scalar, strip-chomp indicator, trailing comment on the key line",
" deploy:\n name: >- # a folded, strip-chomped scalar\n environment:\n",
" deploy:\n name: >- # a folded, strip-chomped scalar",
),
(
# A step's `- run: |` boundary is `run:`'s column, not the dash's column.
# A sibling `env:` key genuinely at that column is real structure, not block-scalar body.
"a step's `- run: |` block scalar body drops, its sibling env: mapping survives",
" - run: |\n echo body\n env:\n TOKEN: xyz\n",
" - run: |\n env:\n TOKEN: xyz",
),
(
# A valid YAML anchor property (`&label`) sits between the colon and the indicator.
"an anchored block scalar (`name: &label |`) is still recognized as a block-scalar key",
" deploy:\n name: &lbl |\n with:\n environment:\n",
" deploy:\n name: &lbl |",
),
(
# A bare sequence item (a matrix string) has no key, so its boundary is the dash's column.
"a bare sequence-item block scalar (`- |`, a matrix string) still drops its body",
" include:\n - |\n TOKEN\n",
" include:\n - |",
),
]
for label, text, want in code_view_cases:
got = _code_view(text)
if got != want:
ok = False
print(f" FAIL _code_view ({label}) -> {got!r}, want {want!r}")
else:
print(f" ok _code_view ({label})")

# The verbatim engine, covering EOL normalization, hashing, and the stale-versus-modified classification.
# It is exercised here rather than only in production, because a latent bug in the comparison would otherwise surface as a false clean on a real fleet run.
canon = "line one\nline two\nline three\n"
Expand Down
Loading