From 79711184e4bb8029d56b8584969083f7cedd2b00 Mon Sep 17 00:00:00 2001 From: Derek Lewis Date: Wed, 12 Aug 2026 02:28:46 +0000 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=8F=97=EF=B8=8F=F0=9F=94=A7=EF=BC=9Al?= =?UTF-8?q?et=20the=20glob=20see=20dot=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Neither `*` nor `**` will match a name that starts with a dot, so every dot-config file in the repo has been slipping past the verify and format tasks unnoticed: `**/*.yml` walked straight past `.github/workflows/`, and `**/*.mjs` never saw `.remarkrc.mjs`. Eighteen files across five tasks were going unchecked. Brace alternation is the way back in, since `fs.glob` has no `dot` option to set. Matching dot names also brings `.git/` within reach of a plain `**`, hence the standing exclusion. Assisted-by: Claude-Code:claude-opus-5 --- build/utils.mts | 44 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/build/utils.mts b/build/utils.mts index 69aba9ed0..a76a5ba9d 100644 --- a/build/utils.mts +++ b/build/utils.mts @@ -32,22 +32,54 @@ const expandDirPattern = (pattern: string) => pattern.endsWith('/') ? `${pattern}**` : pattern; /** - * Matches files by glob pattern, `globby`-style. Two of globby's conveniences - * that `fs.promises.glob` lacks are reproduced here: `!`-prefixed patterns act - * as exclusions (the native API takes those as a separate option), and only - * files are returned (the native API yields directories alongside them). + * Widens a pattern so that wildcards also match dot-prefixed names. Neither + * `*` nor `**` will do so on its own, which quietly kept every dot-config + * file out of the checks: `**` walked past `.github/`, and `*.mjs` never saw + * `.remarkrc.mjs`. Brace alternation is the way back in -- one alternative + * for descending through a dot directory, one for the dot file itself. + * + * A dot directory nested inside another (`.a/.b/`) is past what the syntax + * can express; there is none here, and one would have to be named outright. + * @param {string} pattern The glob pattern to widen. + * @returns {string} The pattern, with its wildcards made dot-aware. + */ +const expandDotPattern = (pattern: string) => { + const segments = pattern.split('/'); + + return segments + .map((segment, index) => { + if (segment === '**') return '{**,**/.*/**}'; + + // Only the basename decides whether a match is a dot file; a wildcard + // in the middle of the path is a directory name, covered above. + const isBasename = index === segments.length - 1; + + return isBasename && segment.startsWith('*') ? `{,.}${segment}` : segment; + }) + .join('/'); +}; + +/** + * Matches files by glob pattern, `globby`-style. Three of globby's + * conveniences that `fs.promises.glob` lacks are reproduced here: + * `!`-prefixed patterns act as exclusions (the native API takes those as a + * separate option), wildcards match dot-prefixed names, and only files are + * returned (the native API yields directories alongside them). * @param {string | string[]} patterns Glob patterns to include, optionally mixed with `!`-prefixed patterns to exclude. * @returns {Promise} The matched file paths, relative to the cwd. */ export async function glob(patterns: string | string[]) { const include = []; - const exclude = []; + // Matching dot names is what puts `.git/` in reach of a plain `**`, and no + // task has any business reading it. Excluded directories are pruned whole, + // dot entries included, so callers need not widen their own exclusions. + const exclude = ['.git/**']; for (const pattern of [patterns].flat()) { if (pattern.startsWith('!')) { exclude.push(expandDirPattern(pattern.slice(1))); } else { - include.push(expandDirPattern(pattern)); + include.push(expandDotPattern(expandDirPattern(pattern))); } } From 12af686482ec4440418af5a34a7a02358d654909 Mon Sep 17 00:00:00 2001 From: Derek Lewis Date: Thu, 13 Aug 2026 03:23:12 +0000 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=8F=97=EF=B8=8F=F0=9F=94=A7=EF=BC=9Af?= =?UTF-8?q?ormat=20the=20files=20that=20escaped=20the=20formatters?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What the tasks find now that they can see dot files: sequence indentation in the semgrep workflow, and a hand-wrapped array in .remarkrc.mjs that biome would rather have one entry per line. Assisted-by: Claude-Code:claude-opus-5 --- .github/workflows/semgrep.yml | 12 +++++------ .remarkrc.mjs | 39 ++++++++++++++++++++++++++++------- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/.github/workflows/semgrep.yml b/.github/workflows/semgrep.yml index ddd5fec59..48c0c9764 100644 --- a/.github/workflows/semgrep.yml +++ b/.github/workflows/semgrep.yml @@ -2,12 +2,12 @@ on: pull_request: {} push: branches: - - main - - master + - main + - master paths: - - .github/workflows/semgrep.yml + - .github/workflows/semgrep.yml schedule: - - cron: '0 0 * * 0' + - cron: '0 0 * * 0' name: Semgrep jobs: semgrep: @@ -18,5 +18,5 @@ jobs: container: image: returntocorp/semgrep@sha256:98c2572fced2474539fd27cab3207ebd8e95e4e7aab4c3b381fdc5e2641d9941 # latest steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - run: semgrep ci + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - run: semgrep ci diff --git a/.remarkrc.mjs b/.remarkrc.mjs index 885b8f84a..4d9e19929 100644 --- a/.remarkrc.mjs +++ b/.remarkrc.mjs @@ -72,14 +72,39 @@ const naturalLanguage = unified().use([ // tagline. Ignoring a phrase here is by its text, not by the rule id // the reporter prints, so multi-word entries keep their spaces. ignore: [ - 'accomplish', 'additional', 'address', 'aggregate', 'attempt', - 'contains', 'ensure', 'equivalent', 'establish', 'function', - 'identical', 'identify', 'immediately', 'inception', 'indicate', - 'interface', 'maintain', 'multiple', 'portion', 'request', - 'require', 'subsequent', 'type', + 'accomplish', + 'additional', + 'address', + 'aggregate', + 'attempt', + 'contains', + 'ensure', + 'equivalent', + 'establish', + 'function', + 'identical', + 'identify', + 'immediately', + 'inception', + 'indicate', + 'interface', + 'maintain', + 'multiple', + 'portion', + 'request', + 'require', + 'subsequent', + 'type', // Wordiness the house style tolerates. - 'all of', 'appropriate', 'however', 'it is', 'it is essential', - 'one particular', 'overall', 'there are', 'there is', + 'all of', + 'appropriate', + 'however', + 'it is', + 'it is essential', + 'one particular', + 'overall', + 'there are', + 'there is', ], }, ], From 6663a825686b5ad4f4dc0050618a33a6ed66d54c Mon Sep 17 00:00:00 2001 From: Derek Lewis Date: Thu, 13 Aug 2026 03:23:12 +0000 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=8F=97=EF=B8=8F=F0=9F=94=A7=EF=BC=9Aw?= =?UTF-8?q?iden=20a=20named=20directory=20to=20its=20dot=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Naming a directory expands to `dir/**`, and a pattern whose own tail is `**` has no basename segment for the dot-file alternative to attach to. So `glob('sub/')` returned everything under it except the dot files -- the one shape where the widening quietly did not apply. Found in review, before this landed. No task used a trailing slash as an include, so nothing was affected in practice. Assisted-by: Claude-Code:claude-opus-5 --- build/utils.mts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/build/utils.mts b/build/utils.mts index a76a5ba9d..481c41db7 100644 --- a/build/utils.mts +++ b/build/utils.mts @@ -41,12 +41,11 @@ const expandDirPattern = (pattern: string) => * A dot directory nested inside another (`.a/.b/`) is past what the syntax * can express; there is none here, and one would have to be named outright. * @param {string} pattern The glob pattern to widen. - * @returns {string} The pattern, with its wildcards made dot-aware. + * @returns {string[]} Patterns which between them match what the one did, dot names included. */ const expandDotPattern = (pattern: string) => { const segments = pattern.split('/'); - - return segments + const widened = segments .map((segment, index) => { if (segment === '**') return '{**,**/.*/**}'; @@ -57,6 +56,13 @@ const expandDotPattern = (pattern: string) => { return isBasename && segment.startsWith('*') ? `{,.}${segment}` : segment; }) .join('/'); + + // A pattern whose own tail is `**` -- which is what naming a directory + // expands to -- has no basename segment to have been widened, so the dot + // files directly beneath it need a pattern of their own. + return segments.at(-1) === '**' + ? [widened, `${segments.slice(0, -1).join('/')}/**/{,.}*`] + : [widened]; }; /** @@ -79,7 +85,7 @@ export async function glob(patterns: string | string[]) { if (pattern.startsWith('!')) { exclude.push(expandDirPattern(pattern.slice(1))); } else { - include.push(expandDotPattern(expandDirPattern(pattern))); + include.push(...expandDotPattern(expandDirPattern(pattern))); } }