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
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,10 @@ files derived from the staged portal JSON already in that run:
GSTR-3B working-paper output and contains exactly one sheet, `GSTR-3B Consolidated`.

A GSTR-2B full-year run produces its own `full-year-workbook.xlsx` when the
staged JSON carries invoice-level records. This is **source-build output**: it
postdates the published `v0.5.1` package, so a user of the released extension
cannot produce it yet. In a source build it contains: a first `ITC summary` sheet stating
staged JSON carries invoice-level records. This is **not in the Chrome Web Store
package**: the Store publication predates this builder, so a user who installed
from the Store cannot produce it. See `docs/PUBLICATION_READINESS.md` for which
distributions carry it. It contains: a first `ITC summary` sheet stating
the portal's own availability totals alongside the GSTR-3B table each heading
feeds -- as prescribed by FORM GSTR-2B under rule 60(7), not asserted by Pack --
then one sheet per present section (B2B, B2BA, CDNR, IMPG). Each invoice row begins with a reconciliation key of the
Expand Down
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ privately; do not open a public issue for security findings.

| Version | Supported |
| -------------------------- | ----------------------------------------- |
| Current release (`0.5.x`) | Security reports and best-effort fixes |
| Current release (`v0.5.1`) | Security reports and best-effort fixes | <!-- x-release-please-version --> |
| Chrome Web Store release | Published beta; reports and fixes |
| Previous releases | Not supported; upgrade to the current one |
| Development/nightly builds | No production support |
Expand Down
17 changes: 14 additions & 3 deletions docs/PUBLICATION_READINESS.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,20 @@ summary` sheet stating the portal's own availability totals and the GSTR-3B
spreadsheet unchanged, the run keeps the tidy CSV instead and reports the
absence rather than emitting a blank or mislabelled workbook.

**Not in a released binary.** This builder postdates `v0.5.1`. A user of the
published package cannot produce a GSTR-2B workbook, and public copy must not
imply otherwise until a release carries it. The source-controlled Store listing draft
**Not in the Chrome Web Store package.** The Store publication predates this
builder, so a user who installed from the Store cannot produce a GSTR-2B
workbook and public copy must not imply otherwise.

For the GitHub release, read `CHANGELOG.md` for the release that first carried
the builder and compare it against the release recorded above. This paragraph
deliberately does not restate the answer. A restatement is wrong on one side of
the release that changes it, and this paragraph has now been wrong on both:
it denied every distribution while the source already carried the builder, and
a correction then asserted the release binary carried it while the published
release still predated the builder and its tree had no
`buildFiledReturnsGstr2bWorkbook` import. Say which distribution a claim
describes, and derive the release side rather than duplicating it.
The source-controlled Store listing draft
names GSTR-2B as supported beta scope and a test binds it to the capability
table, but the live dashboard fields still carry superseded wording: they are
corrected only once `docs/chrome-web-store/dashboard-closeout.md` records the
Expand Down
29 changes: 24 additions & 5 deletions release-please-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,33 @@
{
"type": "generic",
"path": "docs/PUBLICATION_READINESS.md"
},
{
"type": "generic",
"path": "SECURITY.md"
}
],
"changelog-sections": [
{ "type": "feat", "section": "Features" },
{ "type": "fix", "section": "Fixes" },
{ "type": "docs", "section": "Documentation" },
{ "type": "test", "section": "Tests" },
{ "type": "chore", "section": "Maintenance" }
{
"type": "feat",
"section": "Features"
},
{
"type": "fix",
"section": "Fixes"
},
{
"type": "docs",
"section": "Documentation"
},
{
"type": "test",
"section": "Tests"
},
{
"type": "chore",
"section": "Maintenance"
}
]
}
}
Expand Down
94 changes: 89 additions & 5 deletions tests/docs/public-scope-copy.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,25 @@ import { PACK_EXTENSION_DESCRIPTION } from "../../src/extension/manifest-policy"
const rootDir = process.cwd();
const read = (relativePath: string) => readFile(path.join(rootDir, relativePath), "utf8");

// release-please rewrites this line's version on every release of this package.
const RELEASE_BOUND_MARKER = "<!-- x-release-please-version -->";
// This line records some other distribution's version, which release-please must
// not rewrite -- the Chrome Web Store publication moves only on a new submission.
const FIXED_DISTRIBUTION_MARKER = "<!-- pack-fixed-distribution-version -->";

// 1-based line numbers naming `version` without declaring how they stay current.
function unmaintainedVersionLines(text: string, version: string): number[] {
return text
.split("\n")
.map((line, index) => ({ line, number: index + 1 }))
.filter(({ line }) => line.includes(`v${version}`))
.filter(
({ line }) =>
!line.includes(RELEASE_BOUND_MARKER) && !line.includes(FIXED_DISTRIBUTION_MARKER),
)
.map(({ number }) => number);
}

/**
* One claim about what Pack supports lives in eleven files. Correcting it took
* seven review rounds, and every round found the same defect: another copy that
Expand Down Expand Up @@ -291,19 +310,84 @@ describe("public scope copy", () => {
// it had drifted two minor versions -- it named 0.3.x while 0.5.1 shipped, so
// the file telling users which version receives security fixes named a version
// that no longer exists.
//
// It named a `0.N.x` series until the 0.6.0 release, which was a second problem:
// release-please could not bump a series token, so the file could only be kept
// current by someone remembering, and this test failed the release rather than
// preventing the drift. Worse, the series form contradicted the row below it --
// `0.5.x` reads as covering 0.5.0, which "Previous releases | Not supported"
// denies. It now names the exact current release and is bumped by the release.
it("keeps the security policy's supported version bound to the package", async () => {
const version = JSON.parse(await read("package.json")).version as string;
const [major, minor] = version.split(".");
const security = await read("SECURITY.md");
const declared = [...security.matchAll(/`(\d+)\.(\d+)\.x`/g)].map((m) => `${m[1]}.${m[2]}`);
const declared = [...security.matchAll(/`v(\d+\.\d+\.\d+)`/g)].map((match) => match[1]);

expect(declared.length, "SECURITY.md declares no supported version series").toBeGreaterThan(0);
expect(declared.length, "SECURITY.md declares no supported version").toBeGreaterThan(0);
expect(
declared.filter((series) => series !== `${major}.${minor}`),
`SECURITY.md names a version series the package is not on (package.json is ${version}).`,
declared.filter((candidate) => candidate !== version),
`SECURITY.md names a version the package is not on (package.json is ${version}).`,
).toEqual([]);
});

// The assertion above states the invariant; this one states that nobody has to
// remember it. Without the extra-file entry and the annotation, a release bumps
// package.json, leaves SECURITY.md behind, and fails the suite *inside* the
// release workflow -- before `Run Release Please` reaches the tag, so the release
// does not happen at all. That is how v0.6.0 was blocked.
// Three separate files hard-coded `v0.5.1` next to lines that release-please
// already bumps, and each was wrong the moment a release landed: SECURITY.md
// blocked the 0.6.0 release outright, while README and PUBLICATION_READINESS
// told readers a shipped feature was not in any binary. Naming today's version
// by hand is the defect; the annotation is the fix. This fails at the moment
// someone writes the current version unannotated, rather than one release later
// when it has quietly become false.
//
// A line may instead be marked fixed. Not every mention of today's version
// tracks *this* release: `docs/PUBLICATION_READINESS.md` records the Chrome Web
// Store publication, which moves only when a submission is recorded. When the
// Store catches up to the source version that record legitimately names the
// same number, and annotating it would make release-please rewrite it on the
// next source release even though no new submission happened -- rewriting a
// historical fact. The marker states which of the two a line is.
it.each(["README.md", "SECURITY.md", "docs/PUBLICATION_READINESS.md"])(
"never states the current version in %s without saying how it is maintained",
async (file) => {
const version = JSON.parse(await read("package.json")).version as string;

expect(
unmaintainedVersionLines(await read(file), version).map((line) => `${file}:${line}`),
`${file} names v${version} on a line that says nothing about how it is kept current. Add ${RELEASE_BOUND_MARKER} if the line tracks this package's release, or ${FIXED_DISTRIBUTION_MARKER} if it records another distribution's version that must not be rewritten.`,
).toEqual([]);
},
);

// The marker above is an escape hatch, and an untested escape hatch is where a
// guard rots. No file needs it today -- the Store publication is v0.5.0 while
// the package is on 0.5.1 -- so it is exercised directly instead of waiting for
// the collision that makes it load-bearing.
it("classifies each version mention by how the line says it is maintained", () => {
const text = [
"bare mention of v1.2.3",
`tracks the release v1.2.3 ${RELEASE_BOUND_MARKER}`,
`Store publication v1.2.3 ${FIXED_DISTRIBUTION_MARKER}`,
"an older v1.2.2 needs no marker",
"no version here at all",
].join("\n");

expect(unmaintainedVersionLines(text, "1.2.3")).toEqual([1]);
});

it("bumps the security policy as part of the release rather than by hand", async () => {
const config = JSON.parse(await read("release-please-config.json")) as {
packages: Record<string, { "extra-files": { path: string }[] }>;
};

expect(config.packages["."]?.["extra-files"]?.map((file) => file.path)).toContain(
"SECURITY.md",
);
expect(await read("SECURITY.md")).toContain("<!-- x-release-please-version -->");
});

// Return-level advertising is too coarse. Every return is advertised, yet
// GSTR-3B portal JSON and GSTR-2B details Excel ship without their format
// evidence recorded -- so copy could regress to claiming them and every check
Expand Down