Skip to content

Commit b7524bb

Browse files
committed
Add a lint-chmod task to catch stray executable bits
1 parent 10abe66 commit b7524bb

3 files changed

Lines changed: 83 additions & 1 deletion

File tree

external/iccs/CGATS001Compat-v2-micro.icc

100755100644
File mode changed.

gulpfile.mjs

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2311,6 +2311,88 @@ gulp.task("lint-licenses", function (done) {
23112311
});
23122312
});
23132313

2314+
gulp.task("lint-chmod", function (done) {
2315+
console.log("\n### Checking executable bit on tracked files");
2316+
2317+
// Tracked files allowed to keep the executable bit (shebang scripts).
2318+
const EXECUTABLE_FILES = new Set(["test/chromium/test-telemetry.js"]);
2319+
2320+
let lsFiles;
2321+
try {
2322+
lsFiles = execSync("git ls-files -s", { encoding: "utf8" });
2323+
} catch (e) {
2324+
done(e);
2325+
return;
2326+
}
2327+
2328+
const offenders = [];
2329+
for (const line of lsFiles.split("\n")) {
2330+
if (!line) {
2331+
continue;
2332+
}
2333+
// "<mode> <sha> <stage>\t<path>"
2334+
const tab = line.indexOf("\t");
2335+
const mode = line.slice(0, 6);
2336+
const file = line.slice(tab + 1);
2337+
if (mode === "100755" && !EXECUTABLE_FILES.has(file)) {
2338+
offenders.push(file);
2339+
}
2340+
}
2341+
2342+
if (offenders.length === 0) {
2343+
console.log("files checked, no errors found");
2344+
done();
2345+
return;
2346+
}
2347+
2348+
// --fix here also stages the chmod (via `git update-index`), which is
2349+
// unlike every other --fix in `gulp lint` (those only touch the working
2350+
// tree). Restrict the auto-fix to a direct `gulp lint-chmod --fix`
2351+
// invocation so the umbrella `gulp lint --fix` never silently stages.
2352+
const fix =
2353+
process.argv.includes("lint-chmod") && process.argv.includes("--fix");
2354+
if (!fix) {
2355+
for (const file of offenders.sort()) {
2356+
console.log(` Unexpected executable bit: ${file}`);
2357+
}
2358+
done(
2359+
new Error(
2360+
"Executable-bit check failed (run `gulp lint-chmod --fix` to clear, then commit)."
2361+
)
2362+
);
2363+
return;
2364+
}
2365+
2366+
// Drop the bit on disk too: `git update-index --chmod=-x` only edits the
2367+
// index, so a later `git add` would re-read the still-executable working
2368+
// tree and undo the staged chmod.
2369+
for (const file of offenders) {
2370+
try {
2371+
const { mode } = fs.statSync(file);
2372+
fs.chmodSync(file, mode & ~0o111);
2373+
} catch (e) {
2374+
done(e);
2375+
return;
2376+
}
2377+
}
2378+
2379+
// Chunk the path list so we stay well under ARG_MAX.
2380+
const CHUNK = 256;
2381+
for (let i = 0; i < offenders.length; i += CHUNK) {
2382+
const result = spawnSync(
2383+
"git",
2384+
["update-index", "--chmod=-x", "--", ...offenders.slice(i, i + CHUNK)],
2385+
{ stdio: "inherit" }
2386+
);
2387+
if (result.status !== 0) {
2388+
done(new Error("git update-index failed."));
2389+
return;
2390+
}
2391+
}
2392+
console.log(`cleared executable bit on ${offenders.length} file(s)`);
2393+
done();
2394+
});
2395+
23142396
gulp.task("lint", function (done) {
23152397
console.log("\n### Linting JS/CSS/JSON/SVG/HTML files");
23162398

@@ -2375,7 +2457,7 @@ gulp.task("lint", function (done) {
23752457
return;
23762458
}
23772459

2378-
gulp.task("lint-licenses")(done);
2460+
gulp.series("lint-licenses", "lint-chmod")(done);
23792461
});
23802462
});
23812463

test/images/samplesignature.png

100755100644
File mode changed.

0 commit comments

Comments
 (0)