Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/sanity.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Check public-preview file set
shell: bash
run: |
set -euo pipefail

for file in AGENTS.md CLAUDE.md CHANGELOG.md CONTRIBUTING.md LICENSE README.md SECURITY.md manifest.json package.json docs/00_goal.md docs/01_requirements.md docs/02_runbook.md docs/03_status.md docs/04_decisions.md docs/06_mv3_design.md docs/07_manual_verification.md docs/08_manual_verification_result_template.md
for file in .github/dependabot.yml AGENTS.md CLAUDE.md CHANGELOG.md CONTRIBUTING.md LICENSE README.md SECURITY.md manifest.json package.json docs/00_goal.md docs/01_requirements.md docs/02_runbook.md docs/03_status.md docs/04_decisions.md docs/06_mv3_design.md docs/07_manual_verification.md docs/08_manual_verification_result_template.md
do
test -f "$file"
done
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ All notable product changes will be recorded in this file.
- Added unsupported-page safeguards and exact manifest-permission tests.
- Added immediate `Copied!` feedback with timed label restoration.
- Added public-safe manual verification guidance.
- Restricted body and comment extraction to visible `innerText` without hidden
`textContent` fallback.
- Added page title provenance to Markdown output.
- Added structural blockquote boundaries for untrusted body and comment
previews.
- Added regression checks for hidden content, Markdown structure, background
runtime absence, and external communication primitives.

This entry describes the source preview. It is not a release, tag, package, or
Chrome Web Store publication record.
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ a complete GitHub conversation exporter.
- recognizes GitHub Issue pages
- recognizes GitHub Pull Request conversation pages
- extracts the visible title, source URL, body preview, and visible comment snippets
- creates a Markdown preview with explicit limitations and a review-before-sharing warning
- creates a Markdown preview with the title, explicit limitations, and a review-before-sharing warning
- keeps body and comment previews inside an explicit untrusted-content blockquote boundary
- copies the Markdown to the clipboard
- saves the Markdown as a local `.md` file
- fails closed when metadata injection fails
Expand Down Expand Up @@ -70,7 +71,8 @@ See [SECURITY.md](SECURITY.md) for the security policy and reporting route.
defines reusable maintainer handoff and task-packet structures. GitHub Web
Context Exporter is a smaller browser-side entry point that captures only the
currently visible GitHub page context. It does not replace repository-aware
context gathering or generate a complete task packet.
context gathering or generate a complete task packet. The projects do not
automatically transfer files or share a runtime schema.

## Development

Expand Down
4 changes: 2 additions & 2 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ made for earlier preview revisions.

## Report a vulnerability

After the public repository enables GitHub Private Vulnerability Reporting,
use the repository's **Security** tab and select **Report a vulnerability**.
Use GitHub Private Vulnerability Reporting from the repository's **Security**
tab and select **Report a vulnerability**.

Do not place credentials, private repository content, private logs, identifying
screenshots, or exploit details in a public Issue. If the private reporting
Expand Down
2 changes: 2 additions & 0 deletions docs/01_requirements.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Pull Request support is limited to the Conversation page.
- page title
- visible body preview or an explicit unavailable fallback
- visible comment snippets or an explicit unavailable fallback
- body and comment previews structurally marked as untrusted page content

The preview does not claim complete state, label, body, comment, review,
diff, check, or files-changed coverage.
Expand Down Expand Up @@ -66,3 +67,4 @@ diff, check, or files-changed coverage.
- no analytics or cloud sync
- no GitHub write operation
- manual review required before sharing exported Markdown
- no automatic transfer to Maintainer Context Kit
3 changes: 2 additions & 1 deletion docs/02_runbook.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ npm test

The suite covers URL classification, Markdown formatting, filename generation,
manifest permissions, self-contained metadata injection, fail-closed behavior,
unsupported pages, and Copy feedback.
hidden-content exclusion, untrusted Markdown framing, runtime network
boundaries, unsupported pages, and Copy feedback.

## Load unpacked

Expand Down
39 changes: 31 additions & 8 deletions docs/03_status.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
# Status

Last updated: 2026-07-16
Last updated: 2026-07-30

## Current phase

Maintainer-controlled OSS preview candidate.
Maintainer-controlled public OSS preview.

## Implemented

- Chrome Manifest V3 popup
- GitHub Issue and Pull Request Conversation URL classification
- self-contained visible-page metadata injection
- visible title, source URL, body preview, and visible comment snippets
- explicit selector fallbacks
- rendered-visibility checks that reject hidden, inert, transparent, or
non-rendered body/comment elements
- explicit body selectors that do not promote the first comment into a
missing body preview
- fail-closed injection-error behavior
- Markdown preview with limitation and review-before-sharing sections
- title provenance and blockquoted untrusted body/comment previews
- Copy Markdown with immediate `Copied!` feedback and timed restoration
- local Markdown save without the Chrome Downloads API
- exact manifest-permission regression tests
Expand Down Expand Up @@ -48,11 +52,30 @@ There are no host permissions.

## Verification baseline

- automated test suite: 29 tests
- public-safe Issue and Pull Request Conversation checks
- unsupported repository-root check
- Copy and Download checks
- manifest-permission check
- automated test suite: 38 tests in this local candidate
- exact local candidate loaded with `Load unpacked` in an isolated Chrome for
Testing profile on 2026-07-30
- public-safe Issue check covering title, canonical URL, visible body, and
visible comments
- public-safe Pull Request Conversation check covering title, canonical URL,
visible body, and an explicit no-visible-comments fallback
- unsupported repository-root check with no Markdown and disabled Copy/save
- successful user-gesture Copy check, including `Copied!` feedback and timed
restoration
- successful local Markdown save for both the Issue and Pull Request
- manifest-permission check for `activeTab`, `scripting`, and `clipboardWrite`,
with no host permissions

Verification results describe the tested revision only and are not a
production-readiness guarantee.

## Current product interpretation

The extension is a short orientation snapshot, not a faithful full-conversation
export. Body and comment previews are deliberately capped. State, labels,
complete bodies, full comment history, review threads, diffs, and check results
remain outside the current scope.

Maintainer Context Kit is a separate repository-aware workflow. There is no
automatic file import, stdin bridge, or shared runtime schema between the
projects.
9 changes: 9 additions & 0 deletions docs/04_decisions.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,12 @@ export, redaction, or secret-scanner claims.

Reason: the tested local workflow is useful, while broader distribution and
support promises remain out of scope.

## Independent cross-product operation

Decision: keep this extension and Maintainer Context Kit independently
operable. Do not add file import, stdin transfer, or a shared runtime schema
without repeated workflow evidence that manual transfer is a material problem.

Reason: the products have different trust and collection boundaries. Coupling
them now would add maintenance surface without demonstrated user demand.
5 changes: 5 additions & 0 deletions docs/06_mv3_design.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ The extension has no service worker or content-script registration.
6. The popup validates the injection result and fails closed if extraction did
not execute successfully.
7. The formatter creates a visible-page-only Markdown preview.
Page-derived body and comment previews remain inside blockquotes marked as
untrusted content.
8. The user can copy or locally save the Markdown.

## Supported URL patterns
Expand All @@ -42,6 +44,9 @@ Prefer an explicit fallback or extraction failure over a misleading export.
Hidden, collapsed, paginated, dynamically unloaded, diff, check, and
files-changed content is outside the completeness claim.

The extractor uses visible `innerText` for page-derived body and comment
content. It does not fall back to hidden `textContent`.

## Rendering principle

Page-derived content is rendered through `textContent` or form-control
Expand Down
28 changes: 19 additions & 9 deletions docs/07_manual_verification.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Manual Verification Guide

Last updated: 2026-07-16
Last updated: 2026-07-30

This guide verifies the current local extension behavior. It is not a release or store-publishing checklist.

Expand Down Expand Up @@ -48,17 +48,19 @@ If testing on private repository pages, do not paste, publish, screenshot, or sh
4. Confirm the Markdown preview includes:
- `GitHub Issue Context`
- `Source`
- the current document title and page URL under `Source`
- `Limitations`
- `Review Before Sharing`
- `Body Preview`
- `Visible Comments Preview`
- `Suggested Next Use`
5. Click `Copy Markdown`.
6. Confirm the button immediately changes to `Copied!`.
7. Confirm the button returns to `Copy Markdown` after about 1.5 seconds.
8. Paste into a local scratch document and confirm Markdown was copied.
9. Click `Download Markdown`.
10. Confirm a local `.md` file is saved with a repository/page-based filename.
5. Confirm body and comment snippets are blockquoted as untrusted page content.
6. Click `Copy Markdown`.
7. Confirm the button immediately changes to `Copied!`.
8. Confirm the button returns to `Copy Markdown` after about 1.5 seconds.
9. Paste into a local scratch document and confirm Markdown was copied.
10. Click `Download Markdown`.
11. Confirm a local `.md` file is saved with a repository/page-based filename.

## Verify a Pull Request conversation page

Expand All @@ -74,13 +76,15 @@ If testing on private repository pages, do not paste, publish, screenshot, or sh
4. Confirm the Markdown preview includes:
- `GitHub Pull Request Context`
- `Source`
- the current document title and page URL under `Source`
- `Limitations`
- `Review Before Sharing`
- `Body Preview`
- `Visible Comments Preview`
- `Suggested Next Use`
5. Confirm the preview does not claim to include Files changed, diffs, checks, hidden content, or complete review threads.
6. Confirm Copy and Download behave the same as on Issue pages.
5. Confirm body and comment snippets are blockquoted as untrusted page content.
6. Confirm the preview does not claim to include Files changed, diffs, checks, hidden or collapsed content, or complete review threads.
7. Confirm Copy and Download behave the same as on Issue pages.

## Verify unsupported pages

Expand Down Expand Up @@ -116,6 +120,10 @@ Manual verification passes when:

- supported Issue pages produce a Markdown preview
- supported Pull Request conversation pages produce a Markdown preview
- Source records the current document title and page URL
- body and comment snippets remain inside blockquotes as untrusted content
- hidden or collapsed DOM content is not promoted into body or comment previews
- a visible comment is not promoted into a missing body preview
- unsupported pages fail safely
- Copy Markdown works, shows `Copied!`, and restores its label
- Download Markdown saves a local `.md` file
Expand All @@ -131,4 +139,6 @@ Stop and open a follow-up issue if:
- the output claims completeness that is not implemented
- permissions expand unexpectedly
- generated Markdown omits the review-before-sharing warning
- hidden or collapsed DOM text appears in the generated preview
- a comment is mislabeled as the page body
- local save requires a new permission
12 changes: 10 additions & 2 deletions docs/08_manual_verification_result_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Do not expand extraction scope until this result is filled out and any blocking

Choose one:

- [ ] Pass: current behavior is acceptable for continued private iteration.
- [ ] Pass: current behavior is acceptable for the maintainer-controlled public preview.
- [ ] Conditional pass: minor issues recorded below; no privacy, permission, or misleading-output blocker.
- [ ] Fail: stop feature expansion and fix blockers first.

Expand All @@ -45,8 +45,12 @@ Notes:
- [ ] Type is `issue`.
- [ ] Number is shown.
- [ ] Page title is shown or clear fallback appears.
- [ ] Source includes the current document title and page URL.
- [ ] Body Preview appears or clear fallback appears.
- [ ] Visible Comments Preview appears or clear fallback appears.
- [ ] Body and comment snippets are blockquoted as untrusted content.
- [ ] Hidden or collapsed content is not included.
- [ ] A visible comment is not mislabeled as a missing body.
- [ ] Markdown preview includes limitation language.
- [ ] Markdown preview includes review-before-sharing language.

Expand All @@ -62,8 +66,12 @@ Notes:
- [ ] Type is `pull request`.
- [ ] Number is shown.
- [ ] Page title is shown or clear fallback appears.
- [ ] Source includes the current document title and page URL.
- [ ] Body Preview appears or clear fallback appears.
- [ ] Visible Comments Preview appears or clear fallback appears.
- [ ] Body and comment snippets are blockquoted as untrusted content.
- [ ] Hidden or collapsed content is not included.
- [ ] A visible comment is not mislabeled as a missing body.
- [ ] Markdown preview does not claim Files changed, diffs, checks, or complete review threads.

Notes:
Expand Down Expand Up @@ -150,7 +158,7 @@ List issues that may be fixed later.

Choose one:

- [ ] Continue private iteration.
- [ ] Continue the maintainer-controlled public preview.
- [ ] Fix blockers before further development.
- [ ] Re-run manual verification after fixes.

Expand Down
52 changes: 52 additions & 0 deletions test/runtimeBoundary.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import test from "node:test";
import assert from "node:assert/strict";
import { readdir, readFile } from "node:fs/promises";
import { extname } from "node:path";

async function runtimeSource() {
const root = new URL("../src/", import.meta.url);
const pending = [root];
const files = [];

while (pending.length > 0) {
const directory = pending.pop();
const entries = await readdir(directory, { withFileTypes: true });

for (const entry of entries) {
const url = new URL(entry.name, directory);
if (entry.isDirectory()) {
url.pathname += "/";
pending.push(url);
} else if (extname(entry.name) === ".js") {
files.push(await readFile(url, "utf8"));
}
}
}

return files.join("\n");
}

test("manifest keeps the no-background and no-remote-code boundary", async () => {
const manifest = JSON.parse(await readFile(new URL("../manifest.json", import.meta.url), "utf8"));

assert.equal(manifest.background, undefined);
assert.equal(manifest.content_scripts, undefined);
assert.equal(manifest.externally_connectable, undefined);
assert.equal(manifest.update_url, undefined);
});

test("runtime source contains no external communication primitives", async () => {
const source = await runtimeSource();
const forbidden = [
/\bfetch\s*\(/,
/\bXMLHttpRequest\b/,
/\bWebSocket\b/,
/\bEventSource\b/,
/\bsendBeacon\s*\(/,
/\bconnectNative\s*\(/
];

for (const pattern of forbidden) {
assert.equal(pattern.test(source), false, `${pattern} must not appear in runtime source`);
}
});