chore(release): 0.2.3 — workflow-driven releases + artifact attestations + log.json gitignored

Three things bundled:

1. Release workflow at .github/workflows/release.yml fires on every 3-digit-semver tag push. Builds main.js + styles.css in a clean Ubuntu runner, signs all three release assets via actions/attest-build-provenance@v1 (sigstore-backed via OIDC), creates the GitHub Release with notes pulled from release-notes/<tag>.md. Identical to the workflow landing across cite-wide, perplexed, metafetch as a family-wide pattern.

2. release-notes/0.2.3.md authored in marketing-shape per content-farm/context-v/skills/changelog-conventions/SKILL.md "These are marketing artifacts" section. Convention going forward: every release's body lives in the repo at this path before the tag is pushed.

3. log.json now in .gitignore — runtime plugin telemetry that captures at first-run per-vault, never source-of-truth. Was tracked accidentally in earlier commits; this stops the dirty-tree noise on every git status.

Version bumped 0.2.2 → 0.2.3 across manifest.json / package.json / versions.json. No source-code changes — Drop Gate, Recraft generation, Ideogram v3, Magnific search, ImageKit upload all behave identically to 0.2.2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
mpstaton 2026-05-18 03:09:02 -05:00
parent 673e0334dd
commit d3d7a6a626
7 changed files with 154 additions and 6206 deletions

88
.github/workflows/release.yml vendored Normal file
View file

@ -0,0 +1,88 @@
name: Release plugin
# Fires when a 3-digit-semver tag is pushed (e.g. 0.1.6). Builds the plugin
# in a clean Ubuntu runner, signs the produced main.js / manifest.json /
# styles.css with GitHub's artifact-attestation (sigstore-backed), and
# creates the GitHub Release with those three files attached. Anyone
# installing can verify provenance with `gh attestation verify <file>
# --repo lossless-group/metafetch`.
#
# Release notes: if release-notes/<tag>.md exists in the repo at the tagged
# commit, it's used verbatim as the release body. Otherwise the workflow
# falls back to GitHub's --generate-notes. The convention going forward is
# to author the marketing-shape notes in release-notes/<version>.md before
# tagging (per content-farm/context-v/skills/changelog-conventions/SKILL.md
# "These are marketing artifacts" section — every release page is a
# four-audience marketing surface, not a commit-message recap).
on:
push:
tags:
- '[0-9]+.[0-9]+.[0-9]+'
permissions:
contents: write # gh release create / asset upload
id-token: write # OIDC token for sigstore signing
attestations: write # write the attestation to GitHub's attestation API
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Check out tagged commit
uses: actions/checkout@v4
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 10
run_install: false
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build plugin
run: pnpm build
- name: Attest build provenance
uses: actions/attest-build-provenance@v1
with:
subject-path: |
main.js
manifest.json
styles.css
- name: Pick release-notes source
id: notes
run: |
NOTES_FILE="release-notes/${GITHUB_REF_NAME}.md"
if [ -f "$NOTES_FILE" ]; then
echo "found=true" >> "$GITHUB_OUTPUT"
echo "path=$NOTES_FILE" >> "$GITHUB_OUTPUT"
echo "Using release-notes/${GITHUB_REF_NAME}.md as release body"
else
echo "found=false" >> "$GITHUB_OUTPUT"
echo "No release-notes/${GITHUB_REF_NAME}.md found — falling back to --generate-notes"
fi
- name: Create release
env:
GH_TOKEN: ${{ github.token }}
run: |
if [ "${{ steps.notes.outputs.found }}" = "true" ]; then
gh release create "$GITHUB_REF_NAME" \
--title "$GITHUB_REF_NAME" \
--notes-file "${{ steps.notes.outputs.path }}" \
main.js manifest.json styles.css
else
gh release create "$GITHUB_REF_NAME" \
--title "$GITHUB_REF_NAME" \
--generate-notes \
main.js manifest.json styles.css
fi

3
.gitignore vendored
View file

@ -27,3 +27,6 @@ data.json
# Generated by esbuild — ships as a release asset, not from the repo.
styles.css
# Runtime telemetry — captured at plugin load in the dev vault. Not source-of-truth.
log.json

6202
log.json

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
{
"id": "image-gin",
"name": "Image Gin",
"version": "0.2.2",
"version": "0.2.3",
"minAppVersion": "1.8.10",
"description": "Generate AI images, search stock images, and upload to ImageKit CDN.",
"author": "The Lossless Group",

View file

@ -1,6 +1,6 @@
{
"name": "image-gin",
"version": "0.2.2",
"version": "0.2.3",
"description": "Generate AI images, search stock images, and upload to ImageKit CDN.",
"main": "main.js",
"scripts": {

58
release-notes/0.2.3.md Normal file
View file

@ -0,0 +1,58 @@
**Image Gin generates and gates every image that touches your Obsidian vault — and starting with 0.2.3, every release asset is cryptographically attested back to the source code that built it.**
## Why care?
If you write in Obsidian about client-sensitive material — growth charts, dashboard screenshots, photos of a whiteboard at a strategy session — you don't want a default-on third-party uploader silently shipping bytes to a public CDN. Most note-taking-plus-uploader stacks ask "should we upload to Imgur?" The honest answer for anything proprietary is "neither, until you tell me where."
Image Gin asks first. Every dragged or pasted image gets a single confirmation modal: **vault attachments** (private, stays on your disk), your own private **ImageKit** CDN (for material that needs a URL but isn't strictly secret), or anonymous **Imgur** (for genuinely shareable). Pick once per drop; the modal closes; the markdown link lands at your cursor; you keep typing.
Plus: AI image generation via Recraft and Ideogram v3 from a `image_prompt` frontmatter field, stock-image search via Magnific, and CDN upload via ImageKit, all from inside Obsidian.
Open Obsidian → **Settings → Community Plugins → Browse → "Image Gin" → Install → Enable**.
## What 0.2.3 brings
**Cryptographic provenance on every release asset.** Every `main.js`, `manifest.json`, and `styles.css` in this release is signed via GitHub's [artifact attestation system](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations) (sigstore-backed, OIDC-verified) at build time. The bytes you install can be traced back to the exact commit and GitHub Actions workflow run that produced them.
Verify any release asset before you enable the plugin in your vault:
```bash
gh attestation verify main.js --repo lossless-group/image-gin
```
Exit code 0 means the file came out of a legitimate build of the source repo. Anything tampered with mid-flight — a compromised CDN, a maliciously-edited release attachment — fails the verification.
Particularly relevant for a plugin that handles your private imagery. The Drop Gate's whole value proposition is "you decide where your bytes go" — verifiable provenance on the plugin itself extends that same trust posture all the way down to "the plugin you installed is the plugin you think you installed."
## What it changes for users
**Installing from inside Obsidian:** nothing visible. The Community Plugins directory pulls the latest release the same way it always has.
**Auditing before manual install:** verify before you drop files into `<vault>/.obsidian/plugins/image-gin/`. Same `gh attestation verify` command as above; same exit-code-0 contract.
## How the build pipeline works now
A GitHub Actions workflow (`.github/workflows/release.yml`) fires on every 3-digit-semver tag push. In a clean Ubuntu runner it checks out the tagged commit, runs `pnpm build`, signs the three release assets via [`actions/attest-build-provenance@v1`](https://github.com/actions/attest-build-provenance), and creates the GitHub Release with marketing-shape notes pulled from `release-notes/<tag>.md` in the repo.
Provenance is enforced by infrastructure, not maintainer discipline.
## The Lossless Group plugin family
Image Gin sits alongside three sibling plugins, all by [The Lossless Group](https://lossless.group):
| Plugin | What it does |
|---|---|
| [**Cite Wide**](https://community.obsidian.md/plugins/cite-wide) | Stable hex-identifier citations + URL-based dedupe + LLM-paste research conversion |
| **Image Gin** *(this release)* | Recraft + Ideogram image generation, Magnific stock search, ImageKit CDN, drag-gate for every dropped or pasted image |
| [**Perplexed**](https://community.obsidian.md/plugins/perplexed) | Source-cited research from Perplexity, Claude, Perplexica (self-hosted), or LM Studio (local) + per-directory templates |
| [**Metafetch**](https://community.obsidian.md/plugins/metafetch) | Pull OpenGraph metadata into note frontmatter via OpenGraph.io or Microlink |
If Image Gin saves you time, [buy us a coffee](https://buymeacoffee.com/losslessgroup). The plugins are free; the coffee keeps the next one coming.
## Under the hood — what shipped in this commit
- `.github/workflows/release.yml` — the build-attest-release workflow described above. Identical structure to the workflows landing across cite-wide, perplexed, and metafetch as a family-wide pattern
- `release-notes/0.2.3.md` (this file) — convention going forward: each release's marketing-shape body lives in the repo at this path before the tag is pushed
- `log.json` runtime telemetry now in `.gitignore` (it's plugin debug output that captures at first-run per-vault, never source-of-truth — was tracked by accident in earlier commits)
- Version bumped 0.2.2 → 0.2.3 across `manifest.json`, `package.json`, `versions.json`
- No source-code changes — Drop Gate, Recraft generation, Ideogram v3, Magnific search, ImageKit upload all behave identically to 0.2.2

View file

@ -4,5 +4,6 @@
"0.1.1": "1.8.10",
"0.2.0": "1.8.10",
"0.2.1": "1.8.10",
"0.2.2": "1.8.10"
}
"0.2.2": "1.8.10",
"0.2.3": "1.8.10"
}