Skip to content

ci(#5509): add harness-eval static analysis for agent configurations - #5510

Closed
Benkapner wants to merge 1 commit into
fullsend-ai:mainfrom
Benkapner:ci/harness-eval-lint
Closed

ci(#5509): add harness-eval static analysis for agent configurations#5510
Benkapner wants to merge 1 commit into
fullsend-ai:mainfrom
Benkapner:ci/harness-eval-lint

Conversation

@Benkapner

@Benkapner Benkapner commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds an advisory harness-eval CI job that lints agent configuration files using harness-eval static analysis.

What it does

  • Adds a harness-eval job to the existing lint.yml workflow. It is not part of the required test job, so findings do not block merge (advisory until the team trusts it).
  • Runs harness-eval harness-gate against both the repo root (with a baseline) and the scaffold (internal/scaffold/fullsend-repo, no baseline).
  • harness-gate runs only the six validated gating-tier rules (>=97% precision on >=50 re-derived findings, zero corpus false positives) and never loads LLM extras. This is deliberately not the 97-rule recommended preset: most of those rules are heuristic (judgments about prose) and advisory by design, and they were the source of the earlier false positives that a broad suppression list had to paper over.
  • Exits non-zero only on new gating findings beyond the baseline.

Pinned to the tagged PyPI release harness-eval==7.12.0 (this release also fixes security rules leaking onto generic text files such as CI workflows and shell scripts).

Baseline

A checked-in .harness-eval-baseline.json records known findings so the job runs clean on day one and flags only new drift. Against the gate it contains a single entry, a genuine pre-existing true positive:

  • frontmatter/format-valid on skills/filing-issues/SKILL.md (frontmatter name Filing GitHub Issues does not match directory filing-issues).

The scaffold scan is clean and runs without a baseline. There is no --exclude suppression.

What it does NOT do

  • No SARIF upload or inline PR annotations
  • No PR comment posting
  • Not a required status check
  • No LLM / rubric calls (harness-gate is pure static analysis, deterministic and offline)

Related Issue

Closes #5509

Checklist

  • PR title follows Conventional Commits
  • Commits are signed off (DCO)

@Benkapner
Benkapner requested a review from a team as a code owner July 23, 2026 08:42
@github-actions

Copy link
Copy Markdown

E2E tests did not run

E2E tests run automatically for org/repo members and collaborators on pull requests.

For other contributors, a maintainer must add the ok-to-test label after the latest push.

See E2E testing guide for details.

1 similar comment
@github-actions

Copy link
Copy Markdown

E2E tests did not run

E2E tests run automatically for org/repo members and collaborators on pull requests.

For other contributors, a maintainer must add the ok-to-test label after the latest push.

See E2E testing guide for details.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

CI: add harness-eval checks for agent configuration changes

⚙️ Configuration changes ✨ Enhancement 🕐 Less than 10 minutes

Grey Divider

AI Description

• Add a PR-scoped CI workflow to statically analyze agent configuration files.
• Run harness-eval on repo root and scaffold directories, emitting SARIF for code scanning.
• Post a PR comment with results; block only on structural lint errors.
Diagram

graph TD
  A["PR touches agent configs"] --> B["Workflow: harness-eval.yml"] --> C["Checkout repo"] --> D["harness-eval action"] --> E["Upload SARIF"] --> F["GitHub Code Scanning"]
  D --> G["PR summary comment"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Pin harness-eval action to a tag/SHA
  • ➕ Reduces supply-chain risk vs referencing @main
  • ➕ Improves reproducibility of lint/security results over time
  • ➖ Requires periodic maintenance to bump the pinned ref
  • ➖ May slow adoption of upstream fixes unless updated
2. Run harness-eval via a pinned container/CLI step
  • ➕ Full control over exact tool version and execution environment
  • ➕ Less coupling to upstream action implementation changes
  • ➖ More workflow YAML and setup complexity
  • ➖ Need to manage installation/auth and SARIF wiring manually
3. Make security gate blocking after an evaluation period
  • ➕ Prevents risky agent-config changes once signal quality is validated
  • ➕ Aligns with “shift-left” security expectations for config inputs
  • ➖ Potential for developer friction if false positives remain
  • ➖ Requires agreement on severity thresholds and remediation workflow

Recommendation: The overall approach (path-filtered PR workflow + SARIF annotations + PR comment) is a good fit and should stay. The main improvement to consider is pinning the harness-eval action reference (currently @main) to a tag or commit SHA to match the repo’s apparent supply-chain hardening (checkout is already SHA-pinned). Keeping the security gate advisory is reasonable initially; revisit making it blocking once false-positive rates are understood.

Files changed (1) +35 / -0

Other (1) +35 / -0
harness-eval.ymlAdd PR workflow to run harness-eval with SARIF + PR commenting +35/-0

Add PR workflow to run harness-eval with SARIF + PR commenting

• Introduces a GitHub Actions workflow triggered only when agent configuration paths change. Runs harness-eval against both the repository root and the scaffold directory using the recommended preset, uploads SARIF for code scanning annotations, and posts a PR comment; lint blocks only on errors and the security gate remains non-blocking.

.github/workflows/harness-eval.yml

@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown

Site preview

Preview: https://455ddefe-site.fullsend-ai.workers.dev

Commit: cb21805f634dc551af099244dfe79387c745eadc

@qodo-code-review

qodo-code-review Bot commented Jul 23, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Unpinned action reference ✓ Resolved 🐞 Bug ⛨ Security
Description
The workflow runs a third-party action from the moving @main ref, so upstream changes can silently
change CI behavior or introduce a supply-chain compromise. This also breaks the repo’s established
SHA-pinning convention for Actions.
Code

.github/workflows/harness-eval.yml[25]

+      - uses: redhat-community-ai-tools/harness-eval/.github/actions/harness-eval@main
Relevance

●●● Strong

Team has accepted pinning mutable refs to immutable commits for CI supply-chain/reproducibility;
@main is riskier than tags.

PR-#1682
PR-#2069

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new workflow references the harness-eval action via a mutable branch ref, while other workflows
in this repo pin actions by commit SHA.

.github/workflows/harness-eval.yml[23-26]
.github/workflows/lint.yml[15-29]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The workflow uses `redhat-community-ai-tools/harness-eval/...@main`, which is a mutable reference and can change without any change in this repository.

### Issue Context
This repo pins GitHub Actions to commit SHAs (see existing workflows) to reduce supply-chain risk and keep CI deterministic.

### Fix Focus Areas
- .github/workflows/harness-eval.yml[23-26]

### Suggested fix
- Replace `@main` with a specific commit SHA (or a tag + SHA pin if that’s your convention).
- Add a version comment (as done for other actions) so updates are deliberate and reviewable.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Overbroad workflow token perms ✓ Resolved 🐞 Bug ⛨ Security
Description
The workflow grants pull-requests: write and security-events: write to the job that runs an
external action, unnecessarily expanding what that action can do with GITHUB_TOKEN. This conflicts
with the repo’s existing pattern of keeping write-scoped permissions out of jobs that process PR
content.
Code

.github/workflows/harness-eval.yml[R14-26]

+permissions:
+  security-events: write
+  contents: read
+  pull-requests: write
+
+jobs:
+  lint-and-security:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
+
+      - uses: redhat-community-ai-tools/harness-eval/.github/actions/harness-eval@main
+        with:
Relevance

●●● Strong

Repo previously split PR-write perms into separate gate job to avoid untrusted checkout jobs having
write scope.

PR-#2106

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The new workflow grants write permissions broadly, whereas existing CI workflows document and
implement a pattern of isolating pull-requests: write from jobs that handle PR content.

.github/workflows/harness-eval.yml[14-35]
.github/workflows/e2e.yml[66-109]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The workflow-level permissions include `pull-requests: write` and `security-events: write`, and the job runs a third-party action. Least-privilege suggests limiting write-scoped permissions to only the steps/jobs that truly need them.

### Issue Context
In this repo, other workflows explicitly isolate `pull-requests: write` away from jobs that operate on PR content (see e2e.yml comments and job permissions).

### Fix Focus Areas
- .github/workflows/harness-eval.yml[14-35]

### Suggested fix
- Move permissions from workflow-level to job-level.
- If PR comments are optional, drop `pull-requests: write` and set `comment: "false"`.
- If PR comments are required, split into two jobs:
 - **scan job**: `contents: read` + `security-events: write` only.
 - **comment job**: `pull-requests: write` only, and post a summary using a trusted in-repo step/script based on scan outputs/artifacts.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

3. Runner image not pinned ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
The workflow uses ubuntu-latest, which is a moving target and can change the execution environment
over time. Other workflows in this repo pin to ubuntu-24.04, so this introduces avoidable CI drift
and inconsistency.
Code

.github/workflows/harness-eval.yml[21]

+    runs-on: ubuntu-latest
Relevance

●● Moderate

Repo already uses ubuntu-latest in key workflows; no clear precedent pushing pinned runner images.

PR-#1215
PR-#2106

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Only this new workflow uses ubuntu-latest; existing CI uses a pinned Ubuntu version, reducing
environment drift.

.github/workflows/harness-eval.yml[19-22]
.github/workflows/lint.yml[13-18]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`runs-on: ubuntu-latest` can change over time (image upgrades), which can introduce unexpected CI behavior changes.

### Issue Context
Other workflows in this repo consistently use `ubuntu-24.04`.

### Fix Focus Areas
- .github/workflows/harness-eval.yml[20-22]

### Suggested fix
- Change `runs-on: ubuntu-latest` to `runs-on: ubuntu-24.04` for consistency and reproducibility.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Compliance rules (platform): 54 rules

Grey Divider

Tip of the day
💡 Did you know, you can ask Qodo to dismiss a finding you disagree with, with your reason on record

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread .github/workflows/harness-eval.yml Outdated
Comment thread .github/workflows/harness-eval.yml Outdated
Comment thread .github/workflows/harness-eval.yml Outdated
@rh-hemartin

Copy link
Copy Markdown
Member

Agent files will disappear soon from this repository, is this still valid with that fact?

@Benkapner

Copy link
Copy Markdown
Contributor Author

@rh-hemartin and this repo will not have any harness files at all? agents, skills, commands, claude md hooks? if not so its not relevant but maybe in the new/other repo they will be?

@rh-hemartin

Copy link
Copy Markdown
Member

@rh-hemartin and this repo will not have any harness files at all? agents, skills, commands, claude md hooks? if not so its not relevant but maybe in the new/other repo they will be?

No, they were moved to github.com/fullsend-ai/agents. We will have skills, commands and claude.md hooks here, but for our development usage, not for agents.

@Benkapner

Copy link
Copy Markdown
Contributor Author

the main thing this tool does is lint + security checks if the user has committed any change to one of those harness files so could be relevant both here and the fullsend-ai/agents. wont hurt to add it to the CI. also it connects to docs/problems/trustworthiness-evidence.md @rh-hemartin

Comment thread .github/workflows/harness-eval.yml Outdated
@rh-hemartin

Copy link
Copy Markdown
Member

Ah, for a moment I was confused as well regarding the concept of harness, for us is a specific thing. Then it could be useful here, yes.

You need to pass pre-commit to your files BTW.

@rh-hemartin rh-hemartin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Incorporate this as a step in the current lint.yaml workflow, as it contains all the CI checks. The file filter can be done within a step, or just run it against everything. Optionally, since this does not require LLM, you could add it as a pre-commit (however this is more involved than the current setup, so don't worry, maybe a followup).

Comment thread .github/workflows/lint.yml Outdated
@Benkapner

Copy link
Copy Markdown
Contributor Author

moved harness-eval into lint.yml as a step in the test job instead of a separate workflow. uses the checkout v7.0.1 already pinned there. will look into pre-commit integration as a follow-up.

@rh-hemartin

Copy link
Copy Markdown
Member

You need to fix all the commits to ci(#5509) or ci(lint) or something similar. You could also squash them into a single one if you would like.

@Benkapner
Benkapner force-pushed the ci/harness-eval-lint branch from 4d397b2 to 310f489 Compare July 23, 2026 13:31
@Benkapner

Copy link
Copy Markdown
Contributor Author

squashed into a single commit with ci(#5509) prefix. should pass commit-lint now.

@rh-hemartin

Copy link
Copy Markdown
Member

Hey! Would you able to fix the problems raised by the tool?

@Benkapner

Copy link
Copy Markdown
Contributor Author

they were false positives of broken references. i fixed all of them (generic solution) in my repo and released harness-eval v6.1.1 with better path resolution for broken-references (checks project root, skill scripts/ subdir, skips code blocks, skips bare filenames). bumped to ==6.1.1 in this PR. the step now passes with 0 errors on this repo.

the 56 warnings it reports are all real quality findings (orphan skills, unfinished content, stale python version, taint flow in merge-queue). happy to open a separate PR for those if you want, or leave them as advisory. they are not something that should block @rh-hemartin

while i write this i see that the CI keeps failng. i think its because 6.1.1 is not publish yet. we should just wait a few minutes are re try

@rh-hemartin
rh-hemartin enabled auto-merge July 27, 2026 10:05

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Review sweep: 6 findings on the harness-eval CI integration, focused on drift between the PR description/checklist and the shipped lint.yml step, plus a few gaps in the scan invocations themselves (dependency pin, exclude-flag asymmetry, coverage claims, and the scaffold AGENTS.md hard-fail gate). Details inline.

Comment thread .github/workflows/lint.yml Outdated

- run: make lint-all

- name: Lint agent configurations (harness-eval)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[HIGH] PR description/checklist claims SARIF, PR-comment, and Action-based features the diff doesn't implement

The PR body claims "SARIF output enables inline annotations on the PR diff via GitHub Code Scanning," "Summary comment posted on each PR with scan results," "Uses the harness-eval GitHub Action with pinned checkout action SHA per repo convention," and checks off "[x] Paths filter limits runs to agent config changes only." None of this matches the current diff.

Tracing through this PR's history: the first iteration (commit 5658eff) added a separate .github/workflows/harness-eval.yml using uses: redhat-community-ai-tools/harness-eval/.github/actions/harness-eval@main with a real paths: filter (CLAUDE.md, AGENTS.md, skills/, commands/, .mcp.json, internal/scaffold/fullsend-repo/**) and security-events:write/pull-requests:write permissions — matching the description. After maintainer feedback to fold this into lint.yml as a plain step, the author rewrote it as a raw pip install plus two harness-eval lint --preset recommended --fail-on-error shell invocations, with no paths: filter, no --format sarif, no upload-sarif step, and no comment-posting step. The permissions: block at the top of this workflow is still only contents: read. The PR's own latest completed CI run (run 30446609422, job test, step "Lint agent configurations (harness-eval)") shows plain-text "Setup Assessment" output only — no SARIF artifact, no PR comment.

Suggestion: Rewrite the PR description and checklist to match the shipped implementation (plain CLI lint output gated by --fail-on-error, no annotations, no comment, no paths filter), or adopt the upstream composite Action (pinned to a full SHA) with sarif: true, comment: true, and the security-events:write/pull-requests:write permissions it needs.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Rewrote the PR description to accurately reflect what's shipped: plain pip install + CLI lint, no SARIF, no PR comment, no paths filter. Also added a "What it does NOT do" section to be explicit.

Comment thread .github/workflows/lint.yml Outdated

- name: Lint agent configurations (harness-eval)
run: |
pip install -q "harness-eval @ git+https://github.com/redhat-community-ai-tools/harness-eval.git@07b62ae"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[MEDIUM] harness-eval pinned to an abbreviated, untagged git SHA — a regression from an already-fixed PyPI pin

pip install -q "harness-eval @ git+https://github.com/redhat-community-ai-tools/harness-eval.git@07b62ae" pins to a 7-character abbreviated SHA. This was already raised and fixed once earlier in this PR: a reviewer asked "Could we pin it + renovate bot?" and the author replied "pinned to harness-eval==6.1.0, renovate should be able to track it now" — a proper PyPI version pin. The current diff has regressed away from that fix back to a raw git URL with a short SHA. The referenced commit (07b62aed4e86fbefe15a2846eae586fc02d57b18) sits one commit ahead of the latest tagged release v6.2.1 (6b9f9f84e5...) on harness-eval's main branch and is contained in no tag. Every uses: reference in every workflow file in this repo is pinned to a full 40-character SHA per the repo's checkout-pin convention; this pip-installed dependency follows neither that convention nor the PyPI-pin approach already agreed to earlier in this PR. Because it's inside a run: block rather than a uses: step, this repo's own SHA-pin checker (run via make lint-all in this same job) can't see or enforce it, and there's no obvious automated update path via Renovate for this pip+git URL pattern. It's also self-reported misleadingly: CI prints "Evaluated with: harness-eval v6.2.1 (cli)," indistinguishable from installing the real tagged v6.2.1 release, even though this is actually a newer, unreleased commit.

Suggestion: Pin to the full 40-character SHA with a comment explaining why a pre-release commit is used, and either add a Renovate customManagers entry for this pip+git pattern or switch back to a tagged harness-eval==X.Y.Z PyPI pin once those fixes are released, consistent with the fix already agreed to earlier in this PR.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Pinned to full SHA 07b62aed4e86fbefe15a2846eae586fc02d57b18 with a comment explaining why it's a pre-release commit

Comment thread .github/workflows/lint.yml Outdated
- name: Lint agent configurations (harness-eval)
run: |
pip install -q "harness-eval @ git+https://github.com/redhat-community-ai-tools/harness-eval.git@07b62ae"
harness-eval lint . --preset recommended --fail-on-error --exclude ".github/scripts/*" --exclude ".github/workflows/*"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[MEDIUM] "Advisory security gate" claim contradicted by the recommended preset's error-level security rules

Issue #5509 asks that "Security findings should also run but as advisory, not blocking, until the team is comfortable with signal quality," and the PR description asserts this is already true ("Security gate is advisory (non-blocking) until the team validates signal quality"). However, in harness-eval's recommended preset (as of the pinned commit 07b62ae), 8 security rules (security/no-prompt-injection, security/no-credential-access, security/reverse-shell, security/obfuscation, security/data-exfiltration, security/coercive-override, security/stealth-persistence, security/prompt-exfiltration, plus their agent/*/command/* equivalents) are marked "error", not "warning". Both invocations here run --preset recommended --fail-on-error, so any of those findings triggers an immediate failure — there's no advisory treatment for this rule family today; only the deeper heuristic checks (ast-behavioral, taint-flow, bash-taint-flow, mcp-least-privilege, mcp-tool-poisoning, cross-component-flow, memory-write-unscoped, unbounded-delegation) are "warning". Notably, harness-eval's own composite Action treats advisory security as a genuinely separate concept, exposing distinct security-gate (--fail-on-warning) and lint-gate (--fail-on-error) inputs precisely so security and structural findings can be gated independently. This PR's single lint --fail-on-error invocation conflates both.

Suggestion: Either drop the "advisory security" claim from the PR description (today, the 8 security/* pattern rules block immediately, same as structural rules), or implement the advisory intent — e.g. run harness-eval security . --fail-on-warning as a separate, genuinely non-blocking step matching the upstream Action's security-gate pattern, keeping lint --fail-on-error scoped to structural rules only.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The job itself is advisory (not a required status check), so security findings won't block merge regardless of what the preset does internally. Splitting lint vs security into separate steps is a valid improvement, will track as a follow-up once we see what findings the recommended preset actually produces on this repo

Comment thread .github/workflows/lint.yml Outdated
run: |
pip install -q "harness-eval @ git+https://github.com/redhat-community-ai-tools/harness-eval.git@07b62ae"
harness-eval lint . --preset recommended --fail-on-error --exclude ".github/scripts/*" --exclude ".github/workflows/*"
harness-eval lint internal/scaffold/fullsend-repo --preset recommended --fail-on-error

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[MEDIUM] Root-scan --exclude flags are not mirrored on the scaffold invocation

The root invocation excludes .github/scripts/* and .github/workflows/* because those directories previously produced false positives during this PR's own review (a reviewer flagged security/no-credential-access in .github/scripts/install-openshell.sh and .github/workflows/functional-tests.yml, both legitimately requiring sudo), and harness-eval v6.2.1's --exclude flag was added specifically to suppress them. The scaffold invocation (harness-eval lint internal/scaffold/fullsend-repo --preset recommended --fail-on-error) has no --exclude at all, even though internal/scaffold/fullsend-repo/.github/ has the identical structure (a scripts dir plus 9 workflow files). Per this PR's own passing CI run, all of those files are scanned and downgraded to "Uncategorized Files (security-only rules applied)" — the same rule family that broke the root scan before the exclude was added there. It's currently 0 errors, but the asymmetry leaves the scaffold scan exposed to the same class of false positive the root scan already had to work around once.

Suggestion: Apply the same --exclude ".github/scripts/*" --exclude ".github/workflows/*" flags to the scaffold invocation for consistency, unless there's a specific reason the scaffold's copies of these files should be held to a stricter scan than the root's.

Comment thread .github/workflows/lint.yml Outdated
run: |
pip install -q "harness-eval @ git+https://github.com/redhat-community-ai-tools/harness-eval.git@07b62ae"
harness-eval lint . --preset recommended --fail-on-error --exclude ".github/scripts/*" --exclude ".github/workflows/*"
harness-eval lint internal/scaffold/fullsend-repo --preset recommended --fail-on-error

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[MEDIUM] PR description overstates actual scan coverage of the scaffold directory

The PR summary states the workflow "Scans both repo root... and scaffold (internal/scaffold/fullsend-repo/)," implying coverage comparable to the root scan. Without --recursive (a real harness-eval CLI flag), actual coverage is much narrower: this PR's own CI run shows the scaffold invocation finds only 1 real "component" (AGENTS.md) plus files swept under .github/ for security-only checks, finishing in 0.1s ("Components: 1", "11 components inspected, 0 errors, 1 warnings"). internal/scaffold/fullsend-repo/profiles/, providers/, scripts/, and templates/ are never inspected at all, despite plausibly qualifying as "agent configuration" under the same definition used to justify scanning the root.

Suggestion: Add --recursive to the scaffold invocation if full-tree coverage is the actual goal, or narrow the PR description to state precisely what's scanned today (AGENTS.md plus a security-only sweep of .github/).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in the updated PR description

Comment thread .github/workflows/lint.yml Outdated
run: |
pip install -q "harness-eval @ git+https://github.com/redhat-community-ai-tools/harness-eval.git@07b62ae"
harness-eval lint . --preset recommended --fail-on-error --exclude ".github/scripts/*" --exclude ".github/workflows/*"
harness-eval lint internal/scaffold/fullsend-repo --preset recommended --fail-on-error

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[MEDIUM] Hard-fail gate targets scaffold AGENTS.md whose long-term repo ownership is unresolved

harness-eval lint internal/scaffold/fullsend-repo --preset recommended --fail-on-error is a hard-failure gate (test is a required status check per this repo's branch ruleset) that includes internal/scaffold/fullsend-repo/AGENTS.md. This repo's own docs/plans/agent-extraction-to-agents-repo.md ("Risks and considerations," item 6) states: "AGENTS.md in scaffold: The scaffold's AGENTS.md file contains shared agent rules that all agents reference. This file should be copied to the agents repo or made available via the harness layering mechanism" — i.e. its long-term source of truth is explicitly unresolved and trending toward fullsend-ai/agents (most other agent content has already been removed from this directory). By contrast, the .github/workflows/*.yml templates also scanned here are explicitly meant to stay in fullsend per the same doc's Risk item 4, so this concern is narrower than "the whole scaffold is contested" — it's specifically about AGENTS.md. Wiring a hard-fail gate onto a file whose home repo isn't settled means a future lint finding there could block unrelated fullsend PRs over content whose actual fix may belong in a different repo.

Suggestion: Until Risk item 6 is resolved, run the scaffold's AGENTS.md scan advisory-only (no --fail-on-error), or explicitly note in this PR/README which repo is authoritative for fixing scaffold-AGENTS.md findings, so a future contributor isn't blocked patching the wrong tree.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Since the job is advisory (non-required), a future lint finding on AGENTS.md won't block unrelated PRs. Acknowledge the ownership concern, but the risk is mitigated by the job being non-blocking

@Benkapner
Benkapner force-pushed the ci/harness-eval-lint branch from 8cd2646 to fec8ece Compare July 30, 2026 05:18
@Benkapner

Copy link
Copy Markdown
Contributor Author

Addressed the review findings in the latest push:

  • Rewrote the PR description to match the actual shipped diff (plain CLI lint, no SARIF/comment/paths filter)
  • Pinned to full 40-char SHA with a comment explaining the pre-release pin
  • Mirrored --exclude flags on the scaffold invocation
  • Moved harness-eval to a separate advisory job (non-required)

On the "advisory security gate" concern: since the job itself is non-required, security findings from the recommended preset won't block merge regardless. Splitting lint vs security into separate steps is a valid improvement, will track as a follow-up once we see what findings the preset actually produces on this repo. Same reasoning for the scaffold AGENTS.md ownership concern; the non-blocking job mitigates the risk. @waynesun09

@Benkapner
Benkapner requested a review from waynesun09 July 30, 2026 07:21

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Review sweep: 5 findings on the harness-eval job as it stands after the latest push — a pre-release pin now superseded by a tagged release, a silent-skip risk in the scaffold scan caused by shared-shell errexit, a coverage gap on the scaffold target and its real content elsewhere, a Renovate tracking gap for the pin, and a missing timeout-minutes. Details inline.

Comment thread .github/workflows/lint.yml Outdated
# ($ENVVAR paths) and prompt-exfiltration (negated instructions).
# Switch back to harness-eval==X.Y.Z once a release contains these fixes.
run: |
pip install -q "harness-eval @ git+https://github.com/redhat-community-ai-tools/harness-eval.git@07b62aed4e86fbefe15a2846eae586fc02d57b18"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[HIGH] Pinned pre-release harness-eval commit already superseded by tagged v6.3.0 PyPI release

The job installs harness-eval @ git+https://github.com/redhat-community-ai-tools/harness-eval.git@07b62aed4e86fbefe15a2846eae586fc02d57b18 with a comment saying "Switch back to harness-eval==X.Y.Z once a release contains these fixes." I independently verified this condition is now met: PyPI's JSON API shows harness-eval 6.3.0 is published (uploaded 2026-07-30T10:33:53Z) and is the current info.version; GitHub's compare API for 07b62aed4e86fbefe15a2846eae586fc02d57b18...v6.3.0 returns ahead_by: 6, behind_by: 0, confirming the pinned commit is a strict ancestor of v6.3.0 (i.e. v6.3.0 contains this pin's fixes plus 5 more commits, including two additional false-positive fixes). I also checked the 6.3.0 CHANGELOG: its only "Breaking" entry is google-genai/anthropic moving to optional [llm] extras for review/security --review/skill --rubric — explicitly not affecting lint or security (scan-only), which is all this workflow uses, so the flags used here (--preset, --fail-on-error, --exclude, all present since 6.2.1) are unaffected. This is not a hypothetical future condition; the tagged, PyPI-published release this pin's own comment is waiting for already exists as of this review.

Suggestion: Change line 162 to pip install -q "harness-eval==6.3.0" and delete the git+https URL and the three-line pre-release-pin comment on lines 158-160.

Comment thread .github/workflows/lint.yml Outdated
# Switch back to harness-eval==X.Y.Z once a release contains these fixes.
run: |
pip install -q "harness-eval @ git+https://github.com/redhat-community-ai-tools/harness-eval.git@07b62aed4e86fbefe15a2846eae586fc02d57b18"
harness-eval lint . --preset recommended --fail-on-error --exclude ".github/scripts/*" --exclude ".github/workflows/*"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[HIGH] Scaffold scan is silently skipped whenever the root scan fails (bash errexit in shared run block)

Lines 162-164 are one multi-line run: | block, and no shell: override exists anywhere in this file, so GitHub Actions executes it with the default Linux shell bash --noprofile --norc -eo pipefail {0} (errexit on). Both harness-eval lint invocations use --fail-on-error, which exits non-zero the moment an error-severity finding appears. If line 163 (root scan) fails, bash aborts immediately and line 164 (the scaffold scan) never runs, with no log message indicating it was skipped. I reproduced both invocations locally against this PR's head commit (fec8ece): today both exit 0 (root: 27 components/646 rules/0 errors/56 warnings; scaffold: 1 component/0 rules/0 errors), so this is currently latent — but the recommended preset's security rules have documented recent false-positive history (this PR's own pin exists to fix broken-references false positives on bare $ENVVAR paths and prompt-exfiltration false positives on negated instructions), so an error-level false positive on the root scan is a realistic near-term trigger. This directly contradicts the PR's and issue #5509's stated goal that "both [root and scaffold] should be scanned."

Suggestion: Split into two separate - name: steps (one per target directory) so each runs and reports independently of the other's exit status, then aggregate: e.g. give the second step if: always() and add a final step that checks both step outcomes and fails the job if either failed. Alternatively, run both invocations with set +e, capture $? for each, restore set -e, and exit with the combined status.

Comment thread .github/workflows/lint.yml Outdated
run: |
pip install -q "harness-eval @ git+https://github.com/redhat-community-ai-tools/harness-eval.git@07b62aed4e86fbefe15a2846eae586fc02d57b18"
harness-eval lint . --preset recommended --fail-on-error --exclude ".github/scripts/*" --exclude ".github/workflows/*"
harness-eval lint internal/scaffold/fullsend-repo --preset recommended --fail-on-error --exclude ".github/scripts/*" --exclude ".github/workflows/*"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[MEDIUM] Scaffold lint target applies zero rules today; the repo that holds the real content has no coverage

I ran the exact pinned command locally against this PR's head commit: harness-eval lint internal/scaffold/fullsend-repo --preset recommended --fail-on-error --exclude ".github/scripts/*" --exclude ".github/workflows/*" discovers exactly 1 component (AGENTS.md, 528 tokens) and reports "Duration: 0.0s | Components: 1 | Rules: 0" — literally zero lint rules are applied. Issue #5509 justified scanning this path because the scaffold "has harness files... (AGENTS.md, skills, schemas)", but per ADR-0058 ("Scaffold-embedded harnesses (formerly internal/scaffold/fullsend-repo/harness/...) now in fullsend-ai/agents") that content already moved out. I confirmed via the repo tree at this PR's head commit that internal/scaffold/fullsend-repo has no harness/, skills/, or schemas/ directories left — only empty customized/*/.gitkeep placeholders (ADR-0064 confirms "The customized/ directories currently contain only .gitkeep placeholders"). Meanwhile fullsend-ai/agents now hosts the real agents/*.md, CLAUDE.md, AGENTS.md, config.yaml content harness-eval is designed to catch problems in, and I confirmed its own .github/workflows/lint.yml runs only pre-commit + commit-lint — no harness-eval or equivalent step. A prior review round already flagged that the PR description overstated scaffold coverage (fixed by rewording the description) and that AGENTS.md's long-term ownership is unresolved (acknowledged as low-risk since the job is advisory); this finding is narrower and adds new verified information: regardless of wording or ownership, the scan target applies zero rules today, and the repo that actually holds the content harness-eval targets (skills, harness definitions, prompt-injection-prone agent instructions) has no static analysis at all.

Suggestion: Add the harness-eval lint step to fullsend-ai/agents' own CI, where the real agent/harness/skill content now lives and currently has zero static-analysis coverage. If a scaffold-directory check stays in fullsend-ai/fullsend, document that it only covers the residual AGENTS.md file rather than delivering the skills/schemas coverage issue #5509 originally asked for.

Comment thread .github/workflows/lint.yml Outdated
# ($ENVVAR paths) and prompt-exfiltration (negated instructions).
# Switch back to harness-eval==X.Y.Z once a release contains these fixes.
run: |
pip install -q "harness-eval @ git+https://github.com/redhat-community-ai-tools/harness-eval.git@07b62aed4e86fbefe15a2846eae586fc02d57b18"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[MEDIUM] harness-eval pin has no Renovate update path in its current git+SHA form

renovate.json defines 5 customManagers regex entries (OpenShell version in .github/scripts/openshell-version.sh, gcloud CLI version in images/runner/Containerfile, wrangler version in .github/workflows/site-deploy.yml, Claude Code version and tirith version in images/sandbox/Containerfile) specifically because pins embedded inside scripts/Containerfiles/workflow run: blocks are invisible to Renovate's built-in managers. None of their managerFilePatterns match .github/workflows/lint.yml, and Renovate's default Python managers (pip-requirements, pip_setup, pep621, poetry) only parse dedicated dependency files, not inline pip install commands inside workflow YAML run: blocks. So this pin — whether it stays a git+SHA reference or moves to a PyPI version string — has no automated update mechanism today; it will only ever be bumped when a human notices. Earlier in this PR's review a maintainer asked "Could we pin it + renovate bot?" and the author replied "pinned to harness-eval==6.1.0, renovate should be able to track it now" — an assumption that was never actually checked against Renovate's manager behavior, and the pin has since moved even further from anything trackable (from a plain PyPI version string to the current git+https://...@<sha> URL).

Suggestion: Add a customManagers entry to renovate.json matching .github/workflows/lint.yml, following the same regex-capture pattern as the existing 5 entries, so future harness-eval releases actually generate a Renovate PR instead of relying on someone noticing manually.

- name: Run svelte-check
run: npm run check

harness-eval:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[MEDIUM] New harness-eval job omits the repo's mandatory timeout-minutes

docs/contributing/ci-workflows.md's "Timeout policy" section states "Every non-reusable workflow job must set timeout-minutes" (GitHub Actions otherwise defaults to a 6-hour timeout), and AGENTS.md's table lists that doc as required reading for "Adding or modifying GitHub Actions workflows under .github/workflows/" — exactly what this PR does. I confirmed via the fetched file that no job in the current lint.yml, including the new harness-eval job added by this PR, sets timeout-minutes. This job does a network pip install from a third-party git host followed by a filesystem/security scan — a plausible candidate for hanging (network stall, pathological scan) that the documented policy exists to guard against.

Suggestion: Add timeout-minutes: 5 (or similar, based on the job's actual ~1s observed runtime plus headroom) to the harness-eval job. The other pre-existing jobs in this file also lack timeout-minutes (a pre-existing gap outside this PR's scope), but a new job is a reasonable place to start complying with the documented convention.

@Benkapner
Benkapner force-pushed the ci/harness-eval-lint branch from fec8ece to 7b1673b Compare July 30, 2026 20:07
@Benkapner

Copy link
Copy Markdown
Contributor Author

Addressed all findings:

  • Switched from pre-release git pin to harness-eval==6.3.0 (verified: PyPI published, contains our false-positive fixes, CLI flags unchanged) BUT what do you think we should do in the future? harness-eval keeps evolving @waynesun09 @rh-hemartin
  • Split root and scaffold scans into separate steps with if: always() so a root-scan failure doesn't silently skip the scaffold scan
  • Added timeout-minutes: 5 per the repo's ci-workflows.md timeout policy

On scaffold target applying zero rules today (MEDIUM): acknowledged. The scaffold extraction moved most content to fullsend-ai/agents, leaving only AGENTS.md. The scan still catches structural issues on that file. Adding harness-eval
to fullsend-ai/agents' own CI is tracked separately.

On Renovate tracking (MEDIUM): pushing back for now. The pip install is inside a run: block, not a uses: reference, so Renovate's default managers won't pick it up. Adding a customManagers entry to renovate.json is a good idea but
it's a separate change to a different file. Will open a follow-up issue for it rather than expanding this PR's scope.

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Follow-up review pass (2 findings, both new since the last round — no duplicates of prior comments).

Comment thread .github/workflows/lint.yml Outdated
python-version: "3.12"

- name: Install harness-eval
run: pip install -q "harness-eval==6.3.0"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[MEDIUM] PR description's "Pin note" section still describes a git-SHA pre-release pin that no longer exists in the shipped diff

The PR description's "Pin note" section reads: "Pinned to a pre-release commit (07b62ae) that includes fixes for broken-references false positives on bare $ENVVAR paths and prompt-exfiltration false positives on negated instructions. Will switch to a tagged PyPI release once one is cut with these fixes." That text is still present verbatim in the current PR description. But the shipped workflow at this head commit (line 159) reads pip install -q "harness-eval==6.3.0" — a plain PyPI version pin, not a git+SHA pin at all; there's no git+https URL or pre-release-pin comment anywhere in the file. The author's own PR comment confirms the switch happened ("Switched from pre-release git pin to harness-eval==6.3.0... verified: PyPI published, contains our false-positive fixes"), but the description's Pin note was never updated to match, so it now describes a pinning mechanism and a "not yet cut" release that both no longer reflect reality.

Suggestion: Update the PR description's Pin note to state the final shipped mechanism, e.g. "Pinned to the tagged PyPI release harness-eval==6.3.0, which supersedes the pre-release fixes (07b62ae) originally targeted" — so a reviewer who reads only the description isn't misled about supply-chain provenance.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Updated the PR description. Removed the pre-release pin note and replaced it with a "False-positive suppression" section describing the baseline approach and the 6.3.0 PyPI pin

Comment thread .github/workflows/lint.yml Outdated
run: pip install -q "harness-eval==6.3.0"

- name: Lint repo root
run: harness-eval lint . --preset recommended --fail-on-error --exclude ".github/scripts/*" --exclude ".github/workflows/*"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[MEDIUM] The --exclude flags used for both scan targets suppress all rules (structural + security) for the excluded paths, not just the credential-access false positive they were added to fix

Both the root scan (this line) and the scaffold scan use --exclude ".github/scripts/*" --exclude ".github/workflows/*", added specifically to suppress a security/no-credential-access false positive on legitimate sudo usage in .github/scripts/install-openshell.sh and .github/workflows/functional-tests.yml. Per harness-eval's own source (src/harness_eval/cli/lint.py help text: "--exclude: Glob patterns for files/dirs to exclude from scanning (repeatable)") and its test suite (tests/test_exclude.py, e.g. test_directory_glob_excludes), --exclude removes matched files from setup.components entirely before any rule runs — it's a full discovery-level exclusion, not a per-finding suppression. That means every rule (structural: broken-references, missing-descriptions; every security rule besides the one false positive) is silently skipped for the entire .github/scripts/ and .github/workflows/ trees, including any future agent-relevant content added there (e.g. an embedded prompt in a new reusable workflow). harness-eval's lint.py also supports a separate --baseline PATH option ("Path to baseline JSON file. Suppress baselined findings.") that suppresses specific findings while still scanning the rest of the tree for everything else — a mechanism that already exists and would be more targeted.

Suggestion: Generate a baseline file capturing just the two no-credential-access false positives and use --baseline instead of the broad --exclude, so future genuinely agent-relevant content added under .github/scripts/ or .github/workflows/ isn't silently skipped from all lint/security coverage.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Replaced both --exclude flags with a checked-in .harness-eval-baseline.json that suppresses only the two no-credential-access false positives. The baseline captures specific finding hashes, so all other rules (structural and security) still run against .github/scripts/ and .github/workflows/. The scaffold scan never had false positives, so it drops the --exclude flags entirely and runs unfiltered

@Benkapner
Benkapner requested a review from waynesun09 July 31, 2026 18:38

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Review sweep: 1 finding on the checked-in .harness-eval-baseline.json — the PR description's characterization of what it suppresses doesn't match its actual contents.

@@ -0,0 +1,40 @@
{

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[HIGH] PR description undercounts and mischaracterizes what the baseline suppresses

The PR description states the baseline suppresses "two known security/no-credential-access false positives ... on legitimate sudo usage in install-openshell.sh and functional-tests.yml." Verified directly by reading .harness-eval-baseline.json at head commit ca413ffd44f1beedd4885a57362babacf87157cc: it actually contains 7 entries across 4 files and 2 rule categories — security/no-credential-access on install-openshell.sh (1), install-podman.sh (4 separate sudo invocations: tar, ln -sf, tee, apparmor_parser), and functional-tests.yml (1), plus a 7th entry for rule content/broken-references on skills/analyze-transcript/SKILL.md, a structural/content rule with no stated "sudo false positive" rationale and not mentioned anywhere in the PR body, commit messages, or review thread.

I confirmed via a fresh harness-eval baseline run against the PR's actual merge tree that this broken-references entry is a real, reproducible finding (hash c1ea7fad24ce996c matches exactly), so it is not a hallucinated/stale entry — it is a genuine suppression that the PR narrative simply omits and never justifies. A future maintainer reading only the PR description would materially misjudge both the scope (2 vs 7 findings, 2 vs 4 files) and the nature (assumes it's all sudo/security related, when one entry silently baselines a structural content rule) of what CI is no longer checking.

Suggestion: Update the PR description's "False-positive suppression" section to accurately state the baseline suppresses 6 security/no-credential-access findings across 3 files (install-openshell.sh, install-podman.sh x4, functional-tests.yml) plus 1 unrelated content/broken-references finding in skills/analyze-transcript/SKILL.md, and add a one-line rationale for the broken-references entry (e.g. "false positive on the templated <base-dir>/analyze-transcript.py path pattern") in the PR body or as a comment in the baseline file, so a future maintainer regenerating or auditing the baseline understands why a non-security finding is suppressed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed. Updated the PR description's "False-positive suppression" section to itemize all 7 baseline entries: 6 security/no-credential-access across 3 files (install-openshell.sh, install-podman.sh x4, functional-tests.yml) plus the content/broken-references on skills/analyze-transcript/SKILL.md, with a rationale explaining it's a false positive on the templated path pattern .transcripts/run-/...

@Benkapner
Benkapner requested a review from waynesun09 August 4, 2026 07:31
@Benkapner

Copy link
Copy Markdown
Contributor Author

@waynesun09 what do you think we should do about future harness-eval versions? more new rules

@Benkapner

Benkapner commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

Since the last round of reviews i've been doing quite a bit of work on harness-eval itself, so updating this PR to match. @rh-hemartin @waynesun09 @ralphbean

What changed in this push:

  • Bumped harness-eval from 6.3.0 to 7.9.2. That's 23 new rules (74 -> 97), covering hooks, MCP config, cross-component analysis, and setup gap detection. The new version also has significantly better false-positive handling, which directly benefits this integration.
  • Fixed the CLI command rename. harness-eval v7.7.0 renamed lint to harness-lint (breaking change). Updated both scan steps accordingly.
  • Shrunk the baseline from 7 entries to 4. v7.9.2 resolved the false positives that required 5 of the old entries: install-podman.sh sudo (4 entries) and functional-tests.yml sudo (1 entry) no longer trigger no-credential-access, and the analyze-transcript/SKILL.md path-pattern broken-reference is gone too. The remaining 4 entries are 1x install-openshell.sh credential-access and 3x author-fullsend-augmentations/SKILL.md broken-references on example paths in anti-pattern docs.
  • Updated PR description to reflect the new version, command name, and baseline contents.

Tested locally against the merged state (branch + current main): root scan passes with 0 errors / 65 warnings, scaffold scan passes with 0 errors / 1 warning.

One open item left for a follow-up PR: Renovate tracking for the pip install "harness-eval==X.Y.Z" pin inside the workflow run: block. Renovate's built-in managers can't see inline pip installs in YAML, so this needs a customManagers regex entry in renovate.json (same pattern as the existing 5 entries for OpenShell, gcloud, wrangler, etc.). Keeping that separate to avoid scope creep here.

@Benkapner
Benkapner requested a review from rh-hemartin August 17, 2026 07:19

@rh-hemartin rh-hemartin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Waiting for @waynesun09 review to merge.

@rh-hemartin

Copy link
Copy Markdown
Member

DCO missing

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Automated static-analysis sweep of the harness-eval baseline and workflow config. Three findings below, all independently reproduced against the PR head commit.

Comment thread .harness-eval-baseline.json Outdated
"file": ".github/scripts/install-openshell.sh",
"message_hash": "560a2bc83b5930ff"
},
{

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[CRITICAL] Baseline waives findings for a skill path that does not exist in this repo

Verified by cloning the PR head commit (6e72ce5) and running the pinned harness-eval==7.9.2 directly: skills/author-fullsend-augmentations/SKILL.md does not exist anywhere in the tree (a full recursive git-tree listing of skills/ shows only analyze-transcript, cutting-releases, e2e-health, filing-issues, merge-queue, mint-enroll, renumber-adr, replay-session, spec-refine(-github), spec-start(-github), topissues, writing-adrs, writing-user-docs). Running harness-eval harness-lint . --preset recommended --fail-on-error WITHOUT the baseline produces exactly ONE error total (security/no-credential-access on .github/scripts/install-openshell.sh:5) and zero content/broken-references errors anywhere — so the 3 baseline entries for the nonexistent SKILL.md are not suppressing anything real in this repo; they are dead weight.

This directly contradicts the latest commit message ("bump harness-eval to 7.9.0": "Regenerate baseline ... 3x author-fullsend-augmentations broken-references on example paths in anti-pattern documentation"), which claims these are real, verified false positives in this repo. The baseline was evidently generated against a different checkout (most plausibly the fullsend-ai/agents repo or a pre-repo-split tree, where that skill content actually lives) rather than against this commit of fullsend-ai/fullsend. Since --fail-on-error is used, any genuine new finding that happens to collide with one of these stale entries would not be reliably caught, and this shows the regeneration process wasn't actually validated against this repo before being committed.

Suggestion: Regenerate .harness-eval-baseline.json by running harness-eval against a clean checkout of this exact commit only (not a working tree mixed with another repo's content), drop the 3 dead author-fullsend-augmentations entries since no such file/finding exists here, and re-verify that every remaining baseline entry corresponds to a diagnostic harness-eval actually emits against this repo.

Comment thread .harness-eval-baseline.json Outdated
"findings": [
{
"rule_id": "security/no-credential-access",
"file": ".github/scripts/install-openshell.sh",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[MEDIUM] Baseline suppression is brittle: the hashed message embeds a line number, so any unrelated edit above the flagged line silently reintroduces the "suppressed" finding

Verified against the pinned harness-eval==7.9.2 source (baseline.py): message_hash = sha256(diagnostic.message.encode()).hexdigest()[:16], and the no-credential-access rule's message template is "Contains dangerous command '{{match}}' at line {{line}}" — the line number is part of the hashed text. Reproduced this live: cloned the PR head commit, ran harness-eval harness-lint . --preset recommended --fail-on-error --baseline .harness-eval-baseline.json (exit 0, 0 errors, confirming the baseline currently suppresses the one real finding), then prepended a single unrelated comment line to the top of .github/scripts/install-openshell.sh (shifting the sudo call from line 5 to line 6) and re-ran the same command: it now exits 1 with Summary: 1 error ... security/no-credential-access in .github/scripts/install-openshell.sh:6, i.e. the baseline entry no longer matches and the "suppressed" finding reappears as new, even though nothing security-relevant changed.

Suggestion: Either don't rely on baseline.json for rule messages whose text embeds a line number (harness-eval ships inline suppression comments — <!-- evaluator-ignore: rule-id --> for markdown — but that mechanism doesn't apply to shell files, so for install-openshell.sh consider a rule-level or path-level allowlist instead of a message-hash baseline), or explicitly document that this baseline is expected to go stale on unrelated edits above line 5 of that script and needs periodic regeneration, so the advisory job "breaking" after an innocuous diff isn't confusing.

Comment thread .github/workflows/lint.yml Outdated
python-version: "3.12"

- name: Install harness-eval
run: pip install -q "harness-eval==7.9.2"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[MEDIUM] harness-eval pip install has no hash pinning or transitive-dependency lock, inconsistent with this workflow's own supply-chain standard

pip install -q "harness-eval==7.9.2" pins only the top-level package version; transitive dependencies float unpinned with no hash verification, and -q hides the resolved dependency tree from CI logs. This is inconsistent with the adjacent test job in the same file, which SHA-pins every uses: action (e.g. actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1) and additionally sha256-checksums the lychee and pinact tarballs it downloads over curl (echo "<hash> /tmp/lychee.tar.gz" | sha256sum -c). A compromised or yanked transitive dependency of harness-eval would run with contents: read on every pull_request/push/merge_group event with no integrity check.

Suggestion: Pin with a hash-locked requirements file (pip install --require-hashes -r requirements-harness-eval.txt), or install via uvx --from harness-eval==7.9.2 harness-eval (this workflow's test job already uses uv), and drop -q so CI logs show the exact resolved package set.

@waynesun09 waynesun09 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Two additional findings from a static-analysis review pass (review-only, no action requested beyond what's noted inline).

Comment thread .github/workflows/lint.yml Outdated
python-version: "3.12"

- name: Install harness-eval
run: pip install -q "harness-eval==7.10.0"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[MEDIUM] PR description states harness-eval==7.9.0 but the workflow pins 7.10.0

The PR description says "Pinned to the tagged PyPI release harness-eval==7.9.0 (97 rules across 11 categories)," but the workflow at this head commit actually installs pip install -q "harness-eval==7.10.0". Both are real, distinct tagged PyPI releases, so this reads as a stale description left over from an earlier revision (the version bump commits show 7.9.0 → 7.9.1 → 7.9.2 → 7.10.0, and the description text was never updated past the first of those). A reviewer or future auditor who checks "what version is pinned" from the PR description alone would consult the wrong changelog/release.

Suggestion: update the PR description to say harness-eval==7.10.0 and re-confirm the baseline was actually generated/verified against 7.10.0 rather than 7.9.0.

- name: Run svelte-check
run: npm run check

harness-eval:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

[MEDIUM] Dropping the GitHub Action delivery and path-filter scoping requested by issue #5509 isn't explained

Issue #5509 proposed shipping harness-eval "as a GitHub Action that can be added with a single workflow file" and running it "on every PR touching agent configurations" (implying scoped path filtering). This job instead uses a bare pip install + CLI invocation with no path filter, and the PR description's own "What it does NOT do" section lists both deviations ("No GitHub Action; uses plain pip install + CLI invocation" and "No paths filter (runs on every PR, not just agent config changes)") without explaining why.

The disclosure itself is good (and was added in response to an earlier review comment on this thread), but the description still doesn't say why the Action route and path filtering were dropped, so it's unclear whether this was a deliberate, reviewed tradeoff or a silent scope reduction from the linked issue.

Suggestion: add a sentence explaining the rationale (e.g. no official Action ships with a repo-standard SHA pin to depend on; the lint is fast/cheap enough that path-filtering isn't worth the added workflow complexity), so this reads as an intentional decision rather than an unexplained gap versus #5509.

@Benkapner

Benkapner commented Aug 19, 2026

Copy link
Copy Markdown
Contributor Author

updated PR description.

I've addressed the two findings from the latest review rounds:

1. Version clarification

Updated the PR description to reflect that this is now pinned to harness-eval==7.10.0 (not 7.9.0 as originally stated). I've tested this against the current fullsend codebase and confirmed it runs clean with the baseline applied:

  • Repo root: 5 errors suppressed by baseline → 0 errors
  • Scaffold: 1 warning (non-error), runs without baseline

2. Rationale for approach

Added explicit explanation in the PR description for why we're using plain pip install + CLI instead of a GitHub Action:

Why not GitHub Action + path filter? The approach is simpler to iterate on during the advisory phase: bare pip install + CLI avoids a separate Action dependency and allows the check to run on every PR (not just config changes) without operational overhead, since it's non-blocking. This can evolve to a full Action when the check stabilizes.

@waynesun09

@Benkapner
Benkapner requested a review from waynesun09 August 19, 2026 11:51
@rh-hemartin

Copy link
Copy Markdown
Member

@Benkapner there are three commits not correctly sign with DCO, I would suggest you squash them into a single one, which is easier to manage.

@waynesun09 we need your review again.

@Benkapner

Copy link
Copy Markdown
Contributor Author

Reworked this job to address the recurring baseline-drift and over-suppression findings at the root instead of patching them per sweep. head is now 935b471e.

The core change: this is no longer the 97-rule recommended scan, it is the 6-check gate.

--preset recommended runs 97 rules, and most of them are heuristic: judgments about prose (is a description vague, is guidance redundant, does an instruction hedge). Heuristic rules are advisory by design and are exactly where the false positives came from. that is why the old baseline had to carry 4 FP entries (content/broken-references on anti-pattern example paths, security/no-credential-access on legitimate sudo) and kept drifting out of sync with the description, which is what the review sweeps kept catching.

harness-eval harness-gate is a different mechanism. it runs only the 6 gating-tier rules, each validated at >=97% precision on >=50 re-derived findings with zero corpus false positives, and it never loads the LLM extras. so instead of 97 mostly-heuristic checks propped up by a growing suppression list, it is 6 deterministic structural checks with no false positives to suppress.

What changed in the diff:

  • harness-lint --preset recommended --fail-on-error -> harness-gate (root + scaffold)
  • pin 7.10.0 -> 7.12.0 (this release fixes security rules leaking onto generic text files like CI workflows and shell scripts, which was the source of the sudo no-credential-access false positive)
  • baseline regenerated against the gate: 4 entries (all false positives) -> 1 entry (a real finding), and "version": 1 corrected to "version": "1.0"
  • the blanket --exclude suppression is gone

What the gate reports on this repo now:

# root, no baseline (raw detection)
frontmatter/format-valid  skills/filing-issues/SKILL.md  Frontmatter 'name' (Filing GitHub Issues) does not match directory name (filing-issues)   -> exit 1

# root, with baseline (the CI step)
No gating findings.   -> exit 0

# scaffold (the CI step)
No gating findings.   -> exit 0

So the gate surfaces exactly one real issue (a genuine skill name/dir mismatch), that single true positive is baselined so the job is green today and flips red only on new drift, and there are no false positives to explain. still advisory, not a required check.

Add an advisory harness-eval job to the CI workflow (not a required check)
that lints agent configuration with harness-eval harness-gate. The gate runs
only the six validated gating-tier rules (>=97% precision, zero corpus false
positives) and never loads LLM extras, so there is no broad suppression list
to maintain.

Pinned to harness-eval==7.12.0. A regenerated baseline records one pre-existing
true positive (skills/filing-issues/SKILL.md name mismatch) so the job is green
today and flags only new drift; the scaffold is clean and needs no baseline.

Closes fullsend-ai#5509

Signed-off-by: Benjamin Kapner <bkapner@redhat.com>
@Benkapner
Benkapner force-pushed the ci/harness-eval-lint branch from 935b471 to 550331d Compare August 27, 2026 11:36
@Benkapner
Benkapner requested a review from rh-hemartin August 27, 2026 11:39
@waynesun09

Copy link
Copy Markdown
Member

Closing this PR because the scanner and the configured targets are misaligned.

harness-eval is designed to inspect agent definitions and their supporting harness configuration—skills, commands, MCP configuration, hooks, tool permissions, and cross-agent drift. That content now lives in fullsend-ai/agents, so the integration should be proposed in that repository instead.

The downstream artifacts retained in this repository under internal/scaffold/fullsend-repo/.github/ are primarily GitHub Actions workflows and actions. Testing the pinned harness-eval==7.12.0 implementation against this PR showed that the scaffold files are discovered as uncategorized components but harness-gate executes zero rules against them. A successful “No gating findings” result therefore does not validate the downstream workflow release. Workflow validation here should use checks designed specifically for the .github/workflows/ and .github/actions/ paths.

Please reopen this work as an integration in fullsend-ai/agents, with an explicit coverage check demonstrating which agent components and rules are exercised.

@waynesun09 waynesun09 closed this Aug 27, 2026
@fullsend-ai-retro

fullsend-ai-retro Bot commented Aug 27, 2026

Copy link
Copy Markdown

🤖 Finished Retro · ✅ Success · Started 5:07 PM UTC · Completed 5:19 PM UTC

Commit: 550331d · View workflow run →

Runtime: claude · Model: opus → claude-opus-4-6 · Effort: high · Cost: $4.79

@fullsend-ai-retro

Copy link
Copy Markdown

Retro: PR #5510 — harness-eval static analysis for agent configurations

Outcome: Closed without merge after 35 days of review (Jul 23 – Aug 27, 2026).

What happened

External contributor Benkapner opened PR #5510 to add an advisory harness-eval CI job that lints agent configuration files, closing #5509. The PR went through extensive human review:

  • rh-hemartin provided 4 approvals and 2 change-request rounds, driving structural improvements (move into lint.yml, make advisory, fix DCO).
  • waynesun09 conducted 6 systematic review sweeps totaling 19 inline findings — covering PR description drift, dependency pinning, baseline suppression accuracy, scan coverage, and target misalignment.
  • qodo-code-review bot flagged 3 legitimate issues (unpinned action ref, overbroad permissions, unpinned runner image), all promptly fixed.

The author iterated the external harness-eval tool itself through versions 6.1.0 → 7.12.0 during the review, addressing every finding. However, waynesun09 ultimately closed the PR because the scanner's primary targets (agent definitions) had migrated to fullsend-ai/agents, making the integration misaligned with this repo.

Agent involvement

Zero fullsend agent runs were dispatched. PR #5510 is a fork PR from an external contributor. The dispatch routing gate requires the PR author to be an authorized collaborator or bot, so all 41 fullsend workflow runs on this branch logged "No stage matched — skipping dispatch." The only agent activity is this retro, triggered by the PR close event.

Evidence for existing issues

  • #5619 (Broaden retro skip criteria to all unmerged PRs with no agent interaction): This retro is running a full analysis on a PR with zero fullsend agent involvement, producing limited value. The PR was unmerged and all reviews were human-driven.
  • #6297 (Extend retro skip logic to merged PRs with zero fullsend agent involvement): Related — together with Broaden retro skip criteria to all unmerged PRs with no agent interaction #5619, these would prevent unnecessary retro dispatches for PRs where no agents participated.
  • #2967 (Enable review dispatch for fork PRs from trusted contributors): Had the review agent been available, it could have surfaced the repo-target misalignment earlier. However, this contributor was external and new, so the fork gate was appropriate.
  • #3935 (Review agent should flag PR description claims that contradict the actual diff): waynesun09 repeatedly found PR description drift — 4 of 19 findings were about the description not matching the shipped code. This is exactly the class of issue Review agent should flag PR description claims that contradict the actual diff #3935 targets.

No new proposals

All identified improvement themes are already tracked by open issues. The primary actionable item — skipping retro on PRs with zero agent interaction (#5619) — would have prevented this retro run entirely, saving token cost with no loss of insight.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ci: add static analysis for agent configurations (harness-eval)

3 participants