Skip to content

chore(security): resolve code-scanning and Dependabot findings#2087

Merged
chernistry merged 1 commit into
mainfrom
chore/security-tab-remediation
Jun 25, 2026
Merged

chore(security): resolve code-scanning and Dependabot findings#2087
chernistry merged 1 commit into
mainfrom
chore/security-tab-remediation

Conversation

@chernistry

@chernistry chernistry commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator

Clears the open GitHub code-scanning and Dependabot findings.

Changes

  • ci.yml: removed unused checks: write and pull-requests: write from the test and test-macos jobs. The actions that justified them (mikepenz/action-junit-report, ctrf-io/github-test-reporter) are no longer present; the grants and their comments were stale. Both jobs now run with contents: read only. Resolves the Scorecard TokenPermissions finding on those jobs.
  • refurb (15 files): applied the idiom fixes flagged by code scanning: dict()/list() to .copy(), chained comparisons, operator.itemgetter, a list comprehension, and fluent-interface chaining. Behavior-preserving; refurb is clean and the affected module tests pass.
  • vscode dev deps: bumped @babel/core to 7.29.7 and js-yaml to 4.2.0 in packages/vscode/package-lock.json to clear the npm advisories (arbitrary file read via sourceMappingURL; merge-key quadratic DoS).

Verification

  • refurb reports 0 findings on the 15 touched files.
  • ruff check and ruff format clean.
  • 268 module tests pass (replay, routing, cost, approval, schedule, permission, config, worktrees).

The remaining Scorecard TokenPermissions findings are job-level writes that are genuinely required (release tagging, auto-commit-back jobs via create-pull-request, run cleanup) and are triaged separately. PinnedDependencies on build tooling and the trusted-publishing note are triaged as accepted-risk.

Summary by Sourcery

Tighten CI token permissions, apply code-scanning-driven idiom cleanups, and update VS Code dev dependencies to address security advisories.

Enhancements:

  • Adopt safer copying and casting patterns across orchestration, config, routing, replay, and CLI code paths to satisfy static analysis findings.
  • Simplify collection transformations, sorting, and numeric checks for more idiomatic and maintainable core logic.

Build:

  • Update VS Code extension lockfile to bump @babel/core and js-yaml versions that had security advisories.

CI:

  • Restrict CI workflow job permissions to contents: read only where write scopes are no longer needed, resolving token-permissions findings.

Chores:

  • Clear GitHub code-scanning and Dependabot alerts by aligning code with recommended idioms and upgrading vulnerable development dependencies.

Summary by CodeRabbit

  • Bug Fixes

    • Adjusted the verify determinism “bare/observe-only” selection logic to better match the intended execution mode.
    • Improved robustness of config and status parsing by using safer copying patterns to avoid unintended shared-state effects.
  • Chores

    • Reduced CI workflow permissions for the test jobs to a minimal access level.
    • Simplified a few internal copy/sort/serialization steps to keep behavior consistent while improving maintainability.
  • Documentation

    • Updated the CI topology permissions table to reflect the reduced workflow access.

@sourcery-ai

sourcery-ai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Reviewer's Guide

Security-focused cleanup PR: tightens CI job GitHub token permissions, applies refurb-driven Python idiom/safety fixes across core and CLI modules, and bumps VS Code extension dev dependencies to remediate npm advisories, all with behavior preserved and tests passing.

File-Level Changes

Change Details Files
Tighten GitHub Actions CI job token permissions to minimum required scope.
  • Remove stale checks: write and pull-requests: write permissions from the Linux test job, leaving contents: read only.
  • Remove stale checks: write permission from the macOS test job, leaving contents: read only.
  • Update or leave in place comments and structure so remaining job-level write permissions elsewhere can be triaged separately.
.github/workflows/ci.yml
Apply refurb code-scanning idiom and safety fixes in Python core and CLI modules.
  • Replace dict()/list() cloning patterns with .copy() for mappings and lists to make intent explicit and avoid potential subclass surprises.
  • Simplify YAML/JSON section extraction by casting inline before .get() calls, reducing temporary variables.
  • Refine collection handling (e.g., avoid list() around an already-list value, prefer .copy() or direct iteration) to align with modern Python idioms.
  • Switch sort key lambda to operator.itemgetter for clarity and minor efficiency.
  • Adjust comparison and boolean expressions (e.g., chained norms, determinism checks) to idiomatic forms while preserving logic.
  • Use list and set operations that preserve ordering and type (e.g., copying lists instead of re-materializing via list()).
src/bernstein/core/orchestration/schedule_supervisor.py
src/bernstein/core/approval/gate.py
src/bernstein/core/config/home.py
src/bernstein/core/security/permission_policy.py
src/bernstein/core/skills/authoring.py
src/bernstein/sdd/validator.py
src/bernstein/cli/commands/cost.py
src/bernstein/cli/commands/telemetry_cmd.py
src/bernstein/cli/commands/verify_cmd.py
src/bernstein/cli/commands/worktrees_cmd.py
src/bernstein/cli/ui.py
src/bernstein/core/cost/retry_budget.py
src/bernstein/core/replay/gateway.py
src/bernstein/core/routing/bandit_router.py
src/bernstein/core/skills/routing.py
Update VS Code extension dev dependencies to remediate npm security advisories.
  • Bump @babel/core to 7.29.7 in the VS Code extension package lock to address arbitrary file read via sourceMappingURL.
  • Bump js-yaml to 4.2.0 in the VS Code extension package lock to address merge-key quadratic DoS.
  • Ensure lockfile integrity so downstream installs pick up the fixed versions.
packages/vscode/package-lock.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Workflow job permissions were reduced in CI. _verify_determinism now uses a chained identity check for the bare branch. Several CLI, config, and core helpers now use direct .copy() calls or simplified mapping access instead of rebuilding intermediate lists and dicts.

Changes

Workflow and helper updates

Layer / File(s) Summary
Job permissions
.github/workflows/ci.yml
The test and test-macos jobs remove write scopes from their permissions blocks, leaving contents: read.
Determinism branch selection
src/bernstein/cli/commands/verify_cmd.py
The _verify_determinism branch check is rewritten with a chained identity expression.
CLI collection copies
src/bernstein/cli/commands/cost.py, src/bernstein/cli/commands/telemetry_cmd.py, src/bernstein/cli/commands/worktrees_cmd.py, src/bernstein/cli/ui.py
Envelope payloads, environment data, worktree targets, and task_ids are copied directly instead of rebuilt.
Loader mapping access
src/bernstein/core/approval/gate.py, src/bernstein/core/config/home.py, src/bernstein/core/security/permission_policy.py, src/bernstein/core/skills/authoring.py, src/bernstein/sdd/validator.py
Approval, home, permission, trigger-suite, and schema loaders use direct casts, .get(...), and shallow copies.
Schedule audit serialization
src/bernstein/core/orchestration/schedule_supervisor.py
Schedule fire entries and audit receipts are serialized with details.copy() and a list comprehension.
Core helper expression cleanup
src/bernstein/core/cost/retry_budget.py, src/bernstein/core/replay/gateway.py, src/bernstein/core/routing/bandit_router.py, src/bernstein/core/skills/routing.py
Criterion-name checks, fixture sorting, matrix row copying, and cosine zero checks are rewritten without changing the surrounding flow.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • sipyourdrink-ltd/bernstein#1706: Also changes _verify_determinism in src/bernstein/cli/commands/verify_cmd.py and the observe-only branch selection logic.
  • sipyourdrink-ltd/bernstein#1842: Also changes _verify_determinism in src/bernstein/cli/commands/verify_cmd.py and the --expect / --baseline gating path.
  • sipyourdrink-ltd/bernstein#1909: Also updates telemetry_status in src/bernstein/cli/commands/telemetry_cmd.py to resolve share endpoint configuration from environment data.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers changes and verification, but it does not follow the required What/Why/How/Checklist template. Rewrite it using the repository template: add What, Why, How, and checklist items, including docs and tests with completed or N/A boxes.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Title matches the main change by summarizing the security-focused cleanup of code-scanning and Dependabot findings.
Docstring Coverage ✅ Passed Docstring coverage is 94.74% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/security-tab-remediation

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Review-bot acknowledgement summary

  • Must-address findings: 0 (0 acknowledged, 0 open)
  • Informational findings: 2

All must-address findings are resolved or acknowledged.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • In _verify_determinism, the change from expect is None and baseline_run_id is None to expect is None is baseline_run_id alters the logic and produces a chained comparison instead of checking both values for None; this should be reverted or adjusted to preserve the original behavior.
  • In gc_cmd, changing targets = list(reapable) to targets = reapable.copy() may break the subsequent targets.extend(unsaved) if reapable is a set or non-list sequence; ensure targets is explicitly a list before calling extend.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `_verify_determinism`, the change from `expect is None and baseline_run_id is None` to `expect is None is baseline_run_id` alters the logic and produces a chained comparison instead of checking both values for `None`; this should be reverted or adjusted to preserve the original behavior.
- In `gc_cmd`, changing `targets = list(reapable)` to `targets = reapable.copy()` may break the subsequent `targets.extend(unsaved)` if `reapable` is a set or non-list sequence; ensure `targets` is explicitly a list before calling `extend`.

## Individual Comments

### Comment 1
<location path="src/bernstein/cli/commands/verify_cmd.py" line_range="646" />
<code_context>
     fingerprint = fp.compute()

-    if expect is None and baseline_run_id is None:
+    if expect is None is baseline_run_id:
         # Bare mode: observe-only, byte-identical to the original surface.
         # The entry count is only displayed in this branch, so the second WAL
</code_context>
<issue_to_address>
**issue (bug_risk):** The new condition `expect is None is baseline_run_id` is almost certainly a logic bug and changes semantics from the original check.

The previous condition `if expect is None and baseline_run_id is None` clearly required both to be `None`. The new `expect is None is baseline_run_id` is parsed as `(expect is None) is baseline_run_id`, i.e. an identity comparison between a boolean and `baseline_run_id`, which changes behavior and is likely incorrect. If the intent is still to require both values to be `None`, please restore the original condition; if the intent differs (e.g., tri‑state logic), it should be expressed more explicitly.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

fingerprint = fp.compute()

if expect is None and baseline_run_id is None:
if expect is None is baseline_run_id:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): The new condition expect is None is baseline_run_id is almost certainly a logic bug and changes semantics from the original check.

The previous condition if expect is None and baseline_run_id is None clearly required both to be None. The new expect is None is baseline_run_id is parsed as (expect is None) is baseline_run_id, i.e. an identity comparison between a boolean and baseline_run_id, which changes behavior and is likely incorrect. If the intent is still to require both values to be None, please restore the original condition; if the intent differs (e.g., tri‑state logic), it should be expressed more explicitly.

@github-actions

Copy link
Copy Markdown
Contributor

Sonar insights (advisory, no merge-block)

Snapshot of bernstein on the configured Sonar instance:

Metric Value
Coverage 80.1
Code smells 0
Bugs 0
Vulnerabilities 0
Security hotspots 0

Run bernstein doctor sonar locally for the full surface.

This comment is a soft signal. The Sonar scan runs on push to main; the PR check itself never fails on smells.

@github-actions

Copy link
Copy Markdown
Contributor

bernstein doctor observe for PR #2087 (chore/security-tab-remediation): ok=1, warn=1, fail=0, error=0, skipped=2

sonar -- OK (project bernstein)

metric value delta threshold status
coverage_pct 80.1% new 80.0% ok
code_smells 0 new 50 ok
bugs 0 new 0 ok
vulnerabilities 0 new 0 ok
security_hotspots 0 new 0 ok

code-scanning -- WARN (17 open alert(s))

metric value delta threshold status
open_alerts 17 new 0 fail
critical_alerts 0 new 0 ok
high_alerts 1 new 0 warn
medium_alerts 0 new - ok
low_alerts 0 new - ok
Skipped backends (credentials not configured)
  • glitchtip: BERNSTEIN_GLITCHTIP_TOKEN not set
  • dt: DTRACK_URL/TOKEN/PROJECT not set

See docs/observability/unified-doctor.md for backend setup notes.

- ci.yml: drop unused checks:write and pull-requests:write from the test
  and test-macos jobs. The actions that justified them (junit-report,
  test-reporter) are no longer present, so the permissions and their
  comments were stale; the jobs now run with contents:read only.
- Apply the refurb idiom fixes flagged by code scanning across 15 files
  (dict()/list() to .copy(), chained comparisons, operator.itemgetter, a
  list comprehension, and fluent-interface chaining). Behavior-preserving.
- Bump vscode dev dependencies: @babel/core to 7.29.7 and js-yaml to 4.2.0
  to clear the npm advisories (arbitrary file read; merge-key DoS).
@chernistry chernistry force-pushed the chore/security-tab-remediation branch from 771efd6 to edab53e Compare June 25, 2026 10:24
@github-actions github-actions Bot added the docs label Jun 25, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/bernstein/cli/ui.py`:
- Line 159: The task_ids conversion in from_dict is no longer iterable-safe
because it assumes data.get("task_ids") returns a list with .copy(); update the
task_ids assignment to build a new list from whatever iterable is provided so
parsing stays tolerant. Use the existing from_dict method and the task_ids field
as the fix location, and avoid relying on list-specific methods on the incoming
value.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 46a305a3-0740-48b7-89f3-2154955901b3

📥 Commits

Reviewing files that changed from the base of the PR and between 771efd6 and edab53e.

⛔ Files ignored due to path filters (1)
  • packages/vscode/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (17)
  • .github/workflows/ci.yml
  • docs/operations/ci-topology.md
  • src/bernstein/cli/commands/cost.py
  • src/bernstein/cli/commands/telemetry_cmd.py
  • src/bernstein/cli/commands/verify_cmd.py
  • src/bernstein/cli/commands/worktrees_cmd.py
  • src/bernstein/cli/ui.py
  • src/bernstein/core/approval/gate.py
  • src/bernstein/core/config/home.py
  • src/bernstein/core/cost/retry_budget.py
  • src/bernstein/core/orchestration/schedule_supervisor.py
  • src/bernstein/core/replay/gateway.py
  • src/bernstein/core/routing/bandit_router.py
  • src/bernstein/core/security/permission_policy.py
  • src/bernstein/core/skills/authoring.py
  • src/bernstein/core/skills/routing.py
  • src/bernstein/sdd/validator.py
💤 Files with no reviewable changes (1)
  • .github/workflows/ci.yml

Comment thread src/bernstein/cli/ui.py
model=str(data.get("model", "")),
status=str(data.get("status", "idle")),
task_ids=list(cast("list[str]", data.get("task_ids") or [])),
task_ids=cast("list[str]", data.get("task_ids") or []).copy(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Restore iterable-safe conversion for task_ids.

Line 159 now assumes task_ids has a .copy() method; if upstream passes a non-list iterable, from_dict will raise at parse time. Use list(...) to keep the parser tolerant.

Proposed fix
-            task_ids=cast("list[str]", data.get("task_ids") or []).copy(),
+            task_ids=list(cast("Iterable[str]", data.get("task_ids") or [])),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
task_ids=cast("list[str]", data.get("task_ids") or []).copy(),
task_ids=list(cast("Iterable[str]", data.get("task_ids") or [])),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/bernstein/cli/ui.py` at line 159, The task_ids conversion in from_dict is
no longer iterable-safe because it assumes data.get("task_ids") returns a list
with .copy(); update the task_ids assignment to build a new list from whatever
iterable is provided so parsing stays tolerant. Use the existing from_dict
method and the task_ids field as the fix location, and avoid relying on
list-specific methods on the incoming value.

@github-actions

Copy link
Copy Markdown
Contributor

CI Summary

Check Result
Repo hygiene ✅ success
Lint ✅ success
Type check report ✅ success
Tests ✅ success
Tests (macOS) ✅ success
Spelling ✅ success
Dead code ✅ success
Workflow lint ✅ success
Dist size ✅ success
Property (Hypothesis) ✅ success
Snapshot (syrupy) ✅ success
Schemathesis smoke ✅ success
Semgrep custom ✅ success
Bandit ✅ success
pip-audit ✅ success
Beartype ✅ success
Pyright strict zone ✅ success

Coverage and detailed reports are available via Codecov and the Checks tab.

@chernistry chernistry merged commit 95ee18e into main Jun 25, 2026
87 of 88 checks passed
@chernistry chernistry deleted the chore/security-tab-remediation branch June 25, 2026 10:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant