release(1.1.0): publish new version - #206
Conversation
) * fix(security): harden SSRF, upgrades, bind policy, and mutation UX Address the comprehensive code-review findings: validate redirects before following them, reject arbitrary HTTP update sources, require signed remote upgrades, fail closed on non-loopback binds outside containers, reject URL credentials consistently, apply default body limits, drop unsafe restore bypass from HTTP, and make frontend mutations confirm before success UX. Co-authored-by: Robert Goniszewski <goniszewski@users.noreply.github.com> * test: align category filter expectations and simplify update check types Prefer category_id-only list/search params in hook tests, and use a concrete ApiUpdateCheckResult shape to avoid deep DTO instantiation. Co-authored-by: Robert Goniszewski <goniszewski@users.noreply.github.com> * fix(ui): keep Add Bookmark validation copy e2e-compatible Preserve a "valid URL" phrase in the dialog error so existing journey coverage continues to match the safer http(s)/no-credentials check. Co-authored-by: Robert Goniszewski <goniszewski@users.noreply.github.com> * fix(security): keep private update sources working and align fetcher UA - update/service: thread allowPrivateHosts into the real-fetch path so the CLI's local test sources (e.g. --source http://127.0.0.1:9999) are not blocked by the new per-hop redirect guard; private hosts stay rejected by default on the HTTP route - pipeline/fetcher: send the current Grimoire/<version> user-agent (was the stale LittleImp/0.0 string pointing at the old little-imp repo URL) - tests: cover private-source checkForUpdates behavior and the fetcher UA Co-authored-by: Robert Goniszewski <robertgoniszewski@outlook.com> Signed-off-by: Robert Goniszewski <robertgoniszewski@outlook.com> --------- Signed-off-by: Robert Goniszewski <robertgoniszewski@outlook.com> Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Robert Goniszewski <goniszewski@users.noreply.github.com>
- daemon: GET /settings/ai-models lists the OpenRouter model catalog with a free-only filter; guarded by the X-LittleImp-Frontend header, SSRF checks (private-host base URLs and redirect final hops), a 15s timeout, and a 10 MB response cap; upstream error bodies are never relayed - settings: default OpenRouter model becomes openai/gpt-latest (drop the confusing '~' fallback prefix); stored values are normalized on load - frontend: searchable model combobox with free-only toggle, loading/error/ retry states, and custom (typed) model entry - contract, generated API docs, fixtures, and tests updated Signed-off-by: Robert Goniszewski <robertgoniszewski@outlook.com>
* fix: patch release-blocking inconsistencies - install.sh: default LITTLEIMP_VERSION to the current release (was 0.1.0-beta) - extractors: accept www.github.com URLs, restore .git suffix stripping, and send Grimoire/1.0.0 User-Agent from all fetchers - e2e: align mock daemon and specs with the real daemon version and repo URLs - embedding-repository: rebuild the sqlite-vec index in a single atomic transaction instead of thousands of per-row transactions on every boot - docs: refresh release-checklist.md and update-system.md version strings (0.1.0-beta -> 1.0.0) and align test fixtures * chore(release): publish 1.0.1 patch - Bump version identity to 1.0.1 across package manifests, install.sh, API/MCP contract, docs, e2e mocks, and test fixtures - Derive the outgoing User-Agent from the packaged version instead of hardcoding it, so fetchers stop drifting from the release version - Build release archives and fill the Homebrew formula and checksum baselines with the real 1.0.1 artifact SHAs - Add a 1.0.1 changelog entry; regenerate API docs
- Bump version identity to 1.1.0 across package manifests, install.sh, API/MCP contract, docs, e2e mocks, and test fixtures - Carry the 1.0.1 release-identity fixes onto the release branch: installer version default, Grimoire/<version> user-agents, www.github.com / .git handling, atomic sqlite-vec index rebuild - Build 1.1.0 release archives and fill the Homebrew formula and checksum baselines with the real artifact SHAs - Add a 1.1.0 changelog entry; regenerate API docs Co-authored-by: Robert Goniszewski <robertgoniszewski@outlook.com> Signed-off-by: Robert Goniszewski <robertgoniszewski@outlook.com>
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
Resolve all conflicts in favor of the 1.1.0 release branch (superset of the 1.0.1 content cherry-picked earlier plus the 1.1.0 version bumps). Co-authored-by: Robert Goniszewski <robertgoniszewski@outlook.com> Signed-off-by: Robert Goniszewski <robertgoniszewski@outlook.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 82bcda45db
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const combined = `${outputToString(result.stderr)}\n${outputToString(result.stdout)}`; | ||
| const found = [...combined.matchAll(/([A-F0-9]{40}|[A-F0-9]{64})/gi)].map((m) => | ||
| m[1].toUpperCase() | ||
| ); | ||
| const matched = found.some((fp) => allowedFingerprints.includes(fp)); |
There was a problem hiding this comment.
Parse the verified signing-key fingerprint from GPG status
When fingerprint pinning is enabled, this accepts any 40- or 64-hex substring from GPG's human-readable output, not specifically the key that produced the signature. GPG emits signer UIDs in the same stream (for example, Good signature from "..."), so a different key in the user's keyring can place an allowed fingerprint in its UID, sign a malicious archive, and satisfy found.some(...); the archive is then executed by the installer. Invoke GPG with a machine-readable status fd and compare only the fingerprint from VALIDSIG.
Useful? React with 👍 / 👎.
| const res = await fetch(url, { signal: controller.signal, redirect: "follow" }); | ||
| // SSRF guard: reject redirect chains that land on private hosts. Like | ||
| // pipeline/fetcher.ts this only inspects the final hop; intermediate hops | ||
| // are the same accepted risk documented in lib/network.ts. | ||
| if (res.redirected && isPrivateHost(new URL(res.url).hostname)) { |
There was a problem hiding this comment.
Validate catalog redirects before following them
When the configured public OpenRouter base URL redirects through a private or loopback URL, redirect: "follow" contacts that target before the final-host check runs, so the new catalog endpoint remains usable for SSRF despite being described as guarded. Use the shared manual redirect-validation helper so every Location is rejected before the request is sent.
AGENTS.md reference: AGENTS.md:L37-L37
Useful? React with 👍 / 👎.
| className="h-9" | ||
| /> | ||
| </div> | ||
| {error ? ( |
There was a problem hiding this comment.
Preserve custom model entry when the catalog is unavailable
When the catalog request fails—for example while offline or during an OpenRouter outage—the error branch replaces the entire CommandList, while the custom Use … option exists only in the non-error branch. Because this combobox replaces the former text input, users cannot change to a custom OpenRouter model until the remote catalog recovers; keep custom entry available alongside the retry state so this normal settings flow does not depend on the cloud catalog.
AGENTS.md reference: AGENTS.md:L39-L39
Useful? React with 👍 / 👎.
Signs release/*.tar.gz with a detached gpg signature (key auto-detected from the repo git user.email), verifies, runs release:validate --require-signatures, and exports the public key + fingerprint. Co-authored-by: Robert Goniszewski <robertgoniszewski@outlook.com> Signed-off-by: Robert Goniszewski <robertgoniszewski@outlook.com>
|



Summary
Minor release 1.1.0 — the AI provider model picker (new feature), the SSRF / upgrade / bind security hardening, and the 1.0.1 release-identity fixes ported onto the release branch.
Changes
Features
GET /settings/ai-modelsdaemon endpoint.Security / fixes
--allow-unsigned/LITTLEIMP_ALLOW_UNSIGNED_UPGRADE=1is the explicit escape hatch.LITTLEIMP_ALLOW_NON_LOOPBACK_BIND=1.allow_unsafe_no_checksum.JSON.stringify; safe http(s) checks before opening bookmarks.Grimoire/<version>user-agents,www.github.com/ trailing-.githandling, atomic sqlite-vec index rebuild.Release
1.1.0(root + daemon manifests, API/MCP contract, install.sh, docs, e2e).Verification
npm run checkgreen: lint (0 errors), type-check, frontend + daemon unit tests (516 daemon tests),docs:api:check, production build.npm run release:validate+shasum -c(checksum-only). Detached.ascsignatures must be added by the maintainer before publishing — the CLI upgrade path now requires signatures by default (fix(security): harden SSRF, upgrades, bind policy, and mutation UX #201), so signing is mandatory for 1.1.0 remote upgrades unless--allow-unsignedis accepted.