Skip to content

fix: padEditor author-attribute test off-by-one + run backend tests on PRs#36

Merged
JohnMcLear merged 1 commit into
mainfrom
fix/padeditor-test-trailing-newline-and-pr-backend
Jun 2, 2026
Merged

fix: padEditor author-attribute test off-by-one + run backend tests on PRs#36
JohnMcLear merged 1 commit into
mainfrom
fix/padeditor-test-trailing-newline-and-pr-backend

Conversation

@JohnMcLear

Copy link
Copy Markdown
Member

Context

After #35 merged, the post-merge main run showed backend-tests failing — and it turns out it has been red on every main push since #29/#30 (2026-05-16). It was never visible on PRs because the job was skipped for same-repo PRs (see below). Two linked fixes:

1. The actual failure — test off-by-one

1) ep_ai_chat - padEditor > applyEdit
   inserts carry an author attribute even when authorId is empty:
   AssertionError: run covering the newly-appended span should carry an author
   attribute; op={"opcode":"+","chars":1,"lines":1,"attribs":""} opStart=14 opEnd=15

The pad is seeded with Base text"Base text\n". applyEdit({appendText: '\nMore'}) splices before the trailing \n, producing "Base text\nMore\n":

pos 0–8 9 10–13 14
text Base text \n (inserted) More (inserted) \n (seed's original, shifted to tail)

The test skipped ops in the seed prefix (opEnd <= insertStart) but had no upper bound, so it also asserted on pos 14 — the seed's untouched trailing newline, which correctly has no author. The AI must not re-attribute text it never wrote, so the surgical-attribution code is correct; the assertion over-reached.

Fix: bound the check to [insertStart, insertEnd) — exactly the characters applyEdit inserted.

2. Why it hid for ~2.5 weeks — backend skipped on same-repo PRs

backend-tests had an if: guard that ran it only on pushes or fork PRs, and the parent workflow only triggers push on main/master. So same-repo feature-branch PRs got no backend run — failures only surfaced post-merge on main, where nothing blocks on them. This is the same blind spot #35 addressed for the install contract, in another form.

Fix: drop the guard so backend runs on every PR. Backend tests need no secrets, so it's safe for forks too. This PR's own backend run is the proof — it now executes pre-merge.

Verification

This PR exercises the fix on the PR itself (backend now runs on same-repo PRs). Merging only once it's green.

🤖 Generated with Claude Code

…on PRs

Two linked problems surfaced when backend-tests finally ran on a main push:

1. Test off-by-one (the actual failure). The "inserts carry an author
   attribute even when authorId is empty" spec walked atext.attribs and
   required every op past the insert point to carry an author. But
   applyEdit splices the new text in *before* the pad's trailing '\n', so
   that original, AI-untouched newline is shifted to the document tail and
   correctly stays unattributed. The check skipped the seed prefix but had
   no upper bound, so it wrongly asserted on that trailing newline. Bound
   the check to [insertStart, insertEnd) — the span the AI actually wrote.
   The surgical-attribution code was right; only the assertion over-reached.

2. Why nobody noticed for ~2.5 weeks. backend-tests was skipped for
   same-repo PRs (it ran only on pushes or fork PRs), and the parent
   workflow only triggers push on main/master. So same-repo feature-branch
   PRs got no backend run, and this failure only ever showed up post-merge
   on main, where nothing blocks on it. Drop the guard so backend runs on
   every PR; it needs no secrets, so this is safe for forks too.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

Review Summary by Qodo

Fix padEditor test off-by-one and enable backend tests on all PRs

🐞 Bug fix 🧪 Tests

Grey Divider

Walkthroughs

Description
• Fix off-by-one error in padEditor author-attribute test assertion
  - Test was checking trailing newline that AI never wrote
  - Bounded check to exactly inserted character span [insertStart, insertEnd)
• Enable backend tests to run on all PRs, not just forks
  - Previous guard skipped same-repo PRs, hiding failures for 2.5 weeks
  - Failures only surfaced post-merge on main with no blocking mechanism
Diagram
flowchart LR
  A["Test assertion<br/>over-reached"] -->|"Bound to inserted<br/>span only"| B["Correct bounds<br/>insertStart to insertEnd"]
  C["Backend tests<br/>skipped on same-repo PRs"] -->|"Remove if guard"| D["Tests run on<br/>all PRs pre-merge"]

Loading

Grey Divider

File Changes

1. static/tests/backend/specs/padEditor.ts 🐞 Bug fix +10/-3

Bound author-attribute check to inserted span

• Extract appendText variable for clarity and reuse
• Add insertEnd calculation to bound the author-attribute check
• Add upper bound condition to skip seed's trailing newline
• Expand comments explaining the splice position and attribution scope

static/tests/backend/specs/padEditor.ts


2. .github/workflows/backend-tests.yml ⚙️ Configuration changes +8/-5

Enable backend tests on all pull requests

• Remove conditional if: guard that skipped same-repo PRs
• Replace with always-run configuration for backend tests
• Add detailed comment explaining why guard was problematic
• Clarify that backend tests are safe to run on forks (no secrets needed)

.github/workflows/backend-tests.yml


Grey Divider

Qodo Logo

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 2, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0)

Grey Divider


Remediation recommended

1. Unscoped Actions token permissions 🐞 Bug ⛨ Security
Description
Now that backend-tests runs on every PR (including forks), the workflow executes PR-controlled
code (plugin install/tests) without an explicit permissions: scope, inheriting whatever
repo-default GITHUB_TOKEN permissions are configured. This violates least-privilege and can
unintentionally grant broader write capabilities than the job needs.
Code

.github/workflows/backend-tests.yml[R9-16]

Evidence
The caller workflow runs on pull requests and invokes the reusable backend workflow; the backend
workflow checks out and executes the PR’s plugin code but has no explicit permissions: block, so
it inherits repo-default GITHUB_TOKEN permissions.

.github/workflows/test-and-release.yml[1-16]
.github/workflows/backend-tests.yml[1-86]

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

## Issue description
`backend-tests` now intentionally runs on all pull requests, but the workflow does not explicitly scope GITHUB_TOKEN permissions. Because it checks out and runs PR-controlled plugin code, it should declare minimal permissions (typically `contents: read`) so it does not depend on repository-level default token permissions.

## Issue Context
- `test-and-release.yml` triggers on `pull_request` and calls the reusable `backend-tests.yml`.
- `backend-tests.yml` checks out and runs the plugin code, but does not set `permissions:`.

## Fix Focus Areas
- .github/workflows/backend-tests.yml[1-40]
- .github/workflows/test-and-release.yml[1-20]

## What to change
- Add an explicit `permissions:` block (either in the reusable workflow, or in the calling job) such as:
 - `permissions: { contents: read }`
- (Optional hardening) Set `persist-credentials: false` on `actions/checkout` steps that check out PR-controlled code to avoid leaving credentials in the git config.

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


Grey Divider

Qodo Logo

@JohnMcLear JohnMcLear merged commit bf86b21 into main Jun 2, 2026
3 checks passed
@JohnMcLear

Copy link
Copy Markdown
Member Author

Good catch @qodo — fixed in a969549. Since backend-tests now runs PR-controlled code on every PR (including forks), both backend-tests and frontend-tests jobs are now pinned to permissions: contents: read. The release job keeps its own elevated scopes in test-and-release.yml.

JohnMcLear added a commit that referenced this pull request Jun 2, 2026
Pin backend-tests and frontend-tests jobs to permissions: contents:read now that backend runs PR-controlled code on every PR (incl. forks). Follow-up to #36; addresses Qodo finding. ci: commit — does not trigger a release.
@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

🎉 This PR is included in version 1.2.2 🎉

The release is available on:

Your semantic-release bot 📦🚀

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant