mirror of
https://github.com/haperone/local-image-compress.git
synced 2026-07-22 06:44:26 +00:00
fix: limit GitHub release assets to Obsidian install files
This commit is contained in:
parent
0f3da95b48
commit
75f3378776
9 changed files with 21 additions and 14 deletions
1
.github/workflows/release.yml
vendored
1
.github/workflows/release.yml
vendored
|
|
@ -76,6 +76,5 @@ jobs:
|
|||
build/manifest.json
|
||||
build/main.js
|
||||
build/styles.css
|
||||
build/versions.json
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ The release is self-contained. You do not need `pngquant`, `mozjpeg`, Homebrew,
|
|||
|
||||
Source lives in `src-ts`. Root `main.js` is generated and ignored, so readable TypeScript rather than compiled output stays in Git. `npm run build` creates a production-minified local bundle; `npm run test:release` rebuilds it twice, requires deterministic bytes, validates inline WASM, and stages the release allowlist.
|
||||
|
||||
The GitHub release artifact contains only Obsidian install files: `manifest.json`, `main.js`, `styles.css`, and `versions.json`. Production minification is not obfuscation: the complete source remains readable in the repository. Tags are exact numeric SemVer without a `v` prefix. See [RELEASE_POLICY.md](RELEASE_POLICY.md).
|
||||
The GitHub release artifact contains only Obsidian install files: `manifest.json`, `main.js`, and `styles.css`. `versions.json` stays in the repository for compatibility metadata, but it is not uploaded as a release asset. Production minification is not obfuscation: the complete source remains readable in the repository. Tags are exact numeric SemVer without a `v` prefix. See [RELEASE_POLICY.md](RELEASE_POLICY.md).
|
||||
|
||||
### Commands
|
||||
- **Compress all images in note**: Processes images referenced/used in the active note.
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ Release самодостаточный. Устанавливать `pngquant`, `
|
|||
|
||||
Исходники находятся в `src-ts`. Корневой `main.js` генерируется и игнорируется Git, поэтому в репозитории остаётся читаемый TypeScript, а не compiled output. `npm run build` создаёт production-minified локальный bundle; `npm run test:release` собирает его дважды, проверяет детерминированные байты, inline WASM и точный allowlist релиза.
|
||||
|
||||
GitHub release artifact содержит только install-файлы Obsidian: `manifest.json`, `main.js`, `styles.css` и `versions.json`. Минификация не является обфускацией: полный читаемый исходный код остаётся в репозитории. Теги имеют точный numeric SemVer без префикса `v`. См. [RELEASE_POLICY.md](RELEASE_POLICY.md).
|
||||
GitHub release artifact содержит только install-файлы Obsidian: `manifest.json`, `main.js` и `styles.css`. `versions.json` остаётся в репозитории как compatibility metadata, но не загружается как release asset. Минификация не является обфускацией: полный читаемый исходный код остаётся в репозитории. Теги имеют точный numeric SemVer без префикса `v`. См. [RELEASE_POLICY.md](RELEASE_POLICY.md).
|
||||
|
||||
### Возможности
|
||||
- **Локальное сжатие**: PNG через libimagequant-wasm и PNG WASM decode; JPEG через mozjpeg-wasm.
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ installed production bundle locally or in CI.
|
|||
3. Rebuilds production output and requires byte-identical SHA-256 results.
|
||||
4. Runs `verify:root-ts` to prove root `main.js` equals the generated
|
||||
production artifact.
|
||||
5. Recreates `build/` from an explicit four-file allowlist.
|
||||
5. Recreates `build/` from the explicit Obsidian install-file allowlist.
|
||||
|
||||
The production build has no source map and keeps WASM codecs inline, so users
|
||||
do not need package dependencies, external binaries, or separate `.wasm`
|
||||
|
|
@ -40,7 +40,9 @@ GitHub release assets are exactly:
|
|||
- `manifest.json`
|
||||
- `main.js`
|
||||
- `styles.css`
|
||||
- `versions.json`
|
||||
|
||||
`versions.json` remains tracked in the repository for compatibility metadata,
|
||||
but it is not a GitHub Release asset.
|
||||
|
||||
The ignored `build/` staging directory is recreated on every release. It must
|
||||
not contain source workspaces, package metadata, caches, settings, backups,
|
||||
|
|
|
|||
|
|
@ -8,8 +8,7 @@
|
|||
"files": [
|
||||
"manifest.json",
|
||||
"main.js",
|
||||
"styles.css",
|
||||
"versions.json"
|
||||
"styles.css"
|
||||
],
|
||||
"scripts": {
|
||||
"lint": "node scripts/class-wide-gates.js",
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ const { resolveRepositoryLayout } = require("./repository-layout");
|
|||
|
||||
const { repositoryRoot: root } = resolveRepositoryLayout();
|
||||
const buildDir = path.join(root, "build");
|
||||
const releaseFiles = ["manifest.json", "main.js", "styles.css", "versions.json"];
|
||||
const releaseFiles = ["manifest.json", "main.js", "styles.css"];
|
||||
|
||||
fs.rmSync(buildDir, { recursive: true, force: true });
|
||||
fs.mkdirSync(buildDir, { recursive: true });
|
||||
|
|
|
|||
|
|
@ -973,12 +973,18 @@ if (isDevLayout) {
|
|||
assert(rootPackageSource.scripts.build === "npm run build:root", "Standalone package.json build must use the local source build");
|
||||
assert(rootPackageSource.scripts.test.includes("npm run test:ts") && rootPackageSource.scripts["test:release"].includes("npm run verify:release"), "Standalone package.json test scripts must run local source and release verification");
|
||||
}
|
||||
assert(Array.isArray(rootPackageSource.files) && JSON.stringify(rootPackageSource.files) === JSON.stringify(["manifest.json", "main.js", "styles.css", "versions.json"]), "Root package.json files allowlist must contain only Obsidian install artifacts");
|
||||
assert(Array.isArray(rootPackageSource.files) && JSON.stringify(rootPackageSource.files) === JSON.stringify(["manifest.json", "main.js", "styles.css"]), "Root package.json files allowlist must contain only Obsidian install artifacts");
|
||||
assert(!releaseWorkflowSource.includes("build/package.json") && !releaseWorkflowSource.includes("build/README.md") && releaseWorkflowSource.includes("npm run test:release"), "Release workflow still ships dev package metadata or bypasses root test:release");
|
||||
assert(releaseWorkflowSource.includes('"*.*.*"') && releaseWorkflowSource.includes("^[0-9]+\\.[0-9]+\\.[0-9]+$") && !releaseWorkflowSource.includes('"v*"') && !releaseWorkflowSource.includes("GITHUB_REF_NAME#v"), "Release workflow does not combine a dotted tag trigger with exact numeric SemVer validation");
|
||||
assert((releaseWorkflowSource.match(/actions\/checkout@v6/g) || []).length === 2 && (releaseWorkflowSource.match(/actions\/setup-node@v6/g) || []).length === 2 && (releaseWorkflowSource.match(/node-version:\s*"24"/g) || []).length === 2, "Release workflow must use checkout/setup-node v6 and Node 24 in both jobs");
|
||||
const releasePrepareCommand = isDevLayout ? "npm --prefix source-recovery run prepare:release" : "npm run prepare:release";
|
||||
assert(releaseWorkflowSource.includes(releasePrepareCommand) && prepareReleaseSource.includes('["manifest.json", "main.js", "styles.css", "versions.json"]'), "Release workflow does not use the exact install-file staging allowlist");
|
||||
assert(
|
||||
releaseWorkflowSource.includes(releasePrepareCommand)
|
||||
&& prepareReleaseSource.includes('["manifest.json", "main.js", "styles.css"]')
|
||||
&& !releaseWorkflowSource.includes("build/versions.json")
|
||||
&& !prepareReleaseSource.includes('"versions.json"'),
|
||||
"Release workflow does not use the exact supported Obsidian install-file staging allowlist"
|
||||
);
|
||||
assert(validateManifestSource.includes("forbiddenReleaseEntries") && validateManifestSource.includes("package.json must declare a files allowlist"), "Manifest validation does not guard release packaging against dev artifact leaks");
|
||||
assert(validateManifestSource.includes("MIN_API_SURFACE_APP_VERSION") && validateManifestSource.includes("activeWindow/activeDocument/getBasePath"), "Manifest validation does not enforce API-surface minAppVersion");
|
||||
assert(validateManifestSource.includes("manifest.json authorUrl must be a valid URL") && validateManifestSource.includes("must not point to localhost"), "Manifest validation does not reject malformed or local authorUrl values");
|
||||
|
|
|
|||
|
|
@ -136,8 +136,7 @@ for (const [version, minAppVersion] of Object.entries(versions)) {
|
|||
const releaseFiles = [
|
||||
"manifest.json",
|
||||
"main.js",
|
||||
"styles.css",
|
||||
"versions.json"
|
||||
"styles.css"
|
||||
];
|
||||
const forbiddenReleaseEntries = [
|
||||
"cache-backups",
|
||||
|
|
@ -174,7 +173,9 @@ assert(
|
|||
assert(releaseWorkflow.includes('"*.*.*"'), "Release workflow must trigger on dotted tag candidates");
|
||||
assert(releaseWorkflow.includes("^[0-9]+\\.[0-9]+\\.[0-9]+$"), "Release workflow must validate exact numeric SemVer tags");
|
||||
assert(!releaseWorkflow.includes("GITHUB_REF_NAME#v") && !releaseWorkflow.includes('"v*"'), "Release workflow must reject v-prefixed tags");
|
||||
assert(releasePrepare.includes('["manifest.json", "main.js", "styles.css", "versions.json"]'), "Release preparation script must use the explicit install-file allowlist");
|
||||
assert(releasePrepare.includes('["manifest.json", "main.js", "styles.css"]'), "Release preparation script must use the explicit install-file allowlist");
|
||||
assert(!releaseWorkflow.includes("build/versions.json"), "Release workflow must not upload versions.json as a GitHub Release asset");
|
||||
assert(!releasePrepare.includes('"versions.json"'), "Release preparation script must not stage versions.json as a GitHub Release asset");
|
||||
for (const pattern of [
|
||||
/^node_modules\/$/m,
|
||||
/^main\.js$/m,
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ const { resolveRepositoryLayout } = require("./repository-layout");
|
|||
|
||||
const { repositoryRoot: root, sourceRoot } = resolveRepositoryLayout();
|
||||
const rootMainPath = path.join(root, "main.js");
|
||||
const releaseFiles = ["manifest.json", "main.js", "styles.css", "versions.json"];
|
||||
const releaseFiles = ["manifest.json", "main.js", "styles.css"];
|
||||
|
||||
function sha256(buffer) {
|
||||
return crypto.createHash("sha256").update(buffer).digest("hex").toUpperCase();
|
||||
|
|
|
|||
Loading…
Reference in a new issue