Repository navigation
Make Cmdr enterprise-ready #118
Copy link
Copy link
Open
Labels
Description
- Have the right security review answers in place
- Answer "Do you have an SDL, do you keep the software up to date?"
- Does any data leave the EU?
- Data Handling Policy should be fine too
- A reviewer just literally goes to the pricing page or web page, and not spending not much time on it. It must be convincing.
- MDM deployment
- volume licensing (proposal: Volume licensing: how companies buy, manage, and pay for many seats, and how Cmdr should do it #377)
Done items (54 so far, with their dated notes) are in this comment. This description lists only what's open.
Some hardening tasks that are better not public live in a private sister issue: vdavid/cmdr-reports#24. Cyber Essentials moved to #436 (Someday/maybe): where we already comply, for UK prospects; we certify only if a sale needs it.
Data leaving the EU
- Replace Resend (US) for license and notification emails, for example with SMTP through mailcow or an EU provider
- Lock Cloudflare D1 and R2 to the EU jurisdiction (today they're only placed in Eastern Europe)
- Update downloads come from GitHub Releases (US): consider serving them from the EU (our own server, or R2 with the EU jurisdiction)
- EU-specific changes (D1/R2 jurisdiction, Resend, update downloads) are on hold until we've thought through serving US customers too (decided 2026-10-05)
- Then update the "Does data leave the EU?" answer on
/trustand in the privacy policy
Later: stamps with a real issuing body
These come from the plan in the first comment, steps 5–7. Each one gets cheaper once the tasks above are done.
- EU Cyber Resilience Act (CRA): the reporting duty for actively exploited vulnerabilities and severe incidents started on 2026-09-11. Set up the reporting path through ENISA's Single Reporting Platform now, and confirm Cmdr is in scope (a self-review, no lawyer). The technical file, EU declaration of conformity, and CE mark are due by 2027-12-11. (drafts: vdavid/cmdr-reports#45, private. 2026-10-08: David registered as Primary AR on the SRP; CERT-SE rejected the association on 2026-10-09 without a reason (likely: he's styrelsesuppleant, not a signatory). 2026-10-14: David emailed cert@cert.se with the board's signed fullmakt, asking for the reason and whether to re-request. 2026-10-15: CERT-SE said the reason was the gmail address (only company-domain accounts are accepted); David re-requested from a company-domain EU Login, and CERT-SE accepted it the same day: David is the verified Primary AR. A backup contact has an
urgent@getcmdr.comalert path; the fullmakt is signed and filed with the company papers. The backup contact accepted the Secondary AR invite the same day, so the reporting path is set up with a backup. 2026-10-16: the scope self-review is done: Cmdr is in scope, in the default category (self-assessment, no notified body), and its backend services count as part of the product. Next: the 2027-12-11 conformity work (support period, technical file, declaration, CE mark), a walkthrough with the backup contact, and a yearly dry run every October. Kit in the vault,projects/Cmdr/business/2026-10-08 Cmdr CRA …) - On the v0.54.0 release (the first with the Keychain move, "Delete all Cmdr data", Say so in the app when an update fixes a security issue, and what to do #455–Let people turn the operation log off (no undo while it's off), for the CRA #458, and Settings files survive a crash mid-save, and Cmdr tells you when it had to recover a corrupt state file or couldn't confirm a copy is on disk #461): flip the CRA checklist points (2)(d), (2)(f), and (2)(l) to Met in the vault technical file, and Part II (8) too except its lapsed-license test, which waits for the feature lock. Then resubmit CSA STAR with
caiqfill: GRC-08.1 is now Yes, and check whether LOG-05.1 and LOG-05.2 honestly flip with the new digest alerts.
Reactions are currently unavailable
Activity
vdavid commentedon Sep 22, 2026
Here is the advice of an agent that:
docs/security.mdIt's verbatim as the agent gave me:
First, the reframe
On that Little Bird page, exactly one of the four badges was issued by anyone: SOC 2. The GDPR, CCPA, and HIPAA ones are clip-art. There's no GDPR certification body, no CCPA registry, and no such thing as HIPAA-certified software. Anyone can paste those, and plenty of companies do. So the question isn't really "which stamps can I afford", it's "which stamps survive a reviewer clicking them", and on that axis a tiny solo shop can look better than a Series A startup, because the free-but-real ones are mostly about having your house in order.
Free, with a real issuing body or public registry
cargo denyand Renovate you're most of the way to already. There's a sibling, ISO/IEC 18974 (security assurance), same free self-certification route.docs/security.mdproves it end to end (empty entitlements, hardened runtime,source=Notarized Developer ID). You're just not displaying it. "Signed and notarized by Apple, ships zero entitlements" is a stronger claim than most of what's on that Little Bird page, and almost nobody makes it.Free, self-declared, but expected (and where the real process wins are)
These have no badge, but they're what a reviewer actually reads after clicking your badge:
SECURITY.mdand/.well-known/security.txt(RFC 9116). You have neither. Both are 20 minutes of work, and automated vendor scanners check for them. Turn on GitHub private vulnerability reporting while you're there, which also feeds your CRA reporting duty.cargo-cyclonedxplus the npm side, attached to the GitHub release). Issue Make Cmdr enterprise-ready #118 doesn't mention it, but enterprise procurement asks, and the CRA mandates it from 2027.cargo deny, Renovate with a release-age window, hardened runtime with no entitlements, signed and notarized builds, a self-hosted updater, hostile-case test suites on every data-writing path. Writing that up honestly is a day's work and is more convincing than any badge.eujurisdiction restriction, D1 lets you pin the primary region toweur/eeur, and PostHog has an EU Cloud. That turns a squishy answer into "no, apart from your IP hitting GitHub when you download the DMG." Migration isn't free in effort, but it's free in money, and it's the single answer most likely to matter to a European IT department.Don't
What I'd do, in order
SECURITY.md,security.txt, GitHub private vulnerability reporting. An afternoon./trustpage on getcmdr.com that pulls together what's already true: notarized, zero entitlements, self-hosted EU analytics, no cloud AI without your own key, subprocessor list, data-safety page. This is the thing a reviewer actually lands on, and the badges are decoration on it.cargo denystory is written down anyway.One note on sequencing: 1 through 4 are all things you can do without deciding anything, and each one makes 5 and 6 cheaper, because STAR and the CRA technical file both ask you to point at exactly those artifacts.
Want me to start on 1 and 2? I'd draft the
/trustpage as a v0 for you to review, since it's human-facing copy.Sources: CRA explained, CRA reporting obligations, CSA STAR, STAR registry submissions, GitHub artifact attestations, SLSA Build Level 3 with reusable workflows, OpenChain self-certification, OpenSSF Best Practices criteria
feat(website): security reviewers get a paste-ready answer to "Do you…
feat(release): every release asset gets signed SLSA build provenance,…
fix(privacy): natural-language search queries no longer land in the l…
feat(security): publish an OpenSSF Scorecard for the repo, with a REA…
vdavid commentedon Oct 14, 2026
Done items, moved from the description on 2026-10-14 so it lists only what's open. Same structure as the description.
Security review answers
projects/Cmdr/business/2026-10-05 …; finish them through the self-review above, the same way as the policy: open questions marked❓for David) 2026-10-15: done. Self-reviewed with every open question answered: a 48-hour breach notice, liability capped at the license price, the GitHub DPA gap stated openly, and a refund for any license holder who objects to a subprocessor change within their update year. Ready to sign on request (sales@getcmdr.com)./trustdropped it from "Not in place yet".SECURITY.md(no lawyer, by choice, decided 2026-10-14). 2026-10-16: published (216c43e): research in good faith counts as authorized, with no legal action, no police report, and a confirmation of permission if someone else acts; it says what our permission can't cover; Discord is gone from the scope list./trust/development#reviewdescribes that.The first draft is on branch⚠️ callout on every open item below.
worktree-trust-page(not merged yet):SECURITY.md, a fixedsecurity.txt,/trust,/trust/development(the SDL answer), release provenance and SBOMs, and privacy policy fixes. In dev, the pages show aworktree-trust-pagebranch (merged; ships in v0.47.0)mtp-rsandsmb2), then mention it inSECURITY.mdand on/trustSECURITY.md)pricing.astro, around line 173). Now "Ready for your security review", with a link to/trust.features.astrosays Cmdr "ships with a 3B language model", but it's downloaded on demand (the homepage too)cmdr-error-reports, scoped to theerror-reports/folder only (the license backup lives in the same bucket). The privacy policy promises 90 days, and zips from 2026-04 still exist. (Live since 2026-10-05:expire-error-reports-90-days. 159 of 360 zips were past 90 days.setup-cf-infra.shfixed too: it would have added an unscoped rule that deleted the license backups.)hetzner/services/umami/, live 2026-10-06); the privacy policy and/trustsay "deleted after two years"commands/search.rs,ai/translate.rs, the MCPai_searchhandler now log lengths only)summarize_query/summarize_scopeinsearch/engine.rs). Then simplify the privacy policy and/trustwording. (2026-10-05: the search query and scope, the select-by-description prompt, and raw AI replies no longer reach the log. Only file names in free text remain, and the pages now say exactly that.) (2026-10-06: the redactor now scrubs any absolute path and a file name repeated next to its path. One known gap remains and the pages name it: a name logged alone, with no path on its line.)ai_searchincluded, enforced in the backend: 7b7f3cc; ships in v0.47.0)/trust(2026-10-06:docs/notes/proxy-and-tls-inspection-2026-10.md. Manual proxy, env-var proxy, and company root CAs work. Since then, a sharedcmdr-httpclient honors PAC files, auto-discovery (WPAD), the bypass list, andNO_PROXY, and never proxies loopback; ships in the release after 0.50.0. Not supported: proxy sign-in beyond URL credentials, SOCKS)codesign -d --entitlements -) and bumpverifiedAgainstintrust.ts(v0.47.0: empty;verifiedAgainstis 0.47.0)gh attestation verifyon the DMG and drop the "from the next release on" wording (v0.47.0: provenance verifies; wording dropped for provenance)gh attestation verify … --predicate-type https://cyclonedx.org/bom) and drop "from the next release on" from the SBOM wording. v0.47.0's SBOM attestations failed on a missingserialNumber, fixed inrelease.yml(61e50e8f3). (v0.50.0 verifies; wording dropped.verifiedAgainstis 0.50.0.)releaseenvironment). (2026-10-08, v0.51.0:ci-gateand the CodeQL gate passed; provenance and SBOM verify with--signer-workflow …/release-pipeline.yml, so/trustclaims SLSA Build Level 3; the signed, notarized, stapled.pkgandCmdr_0.51.0.intoto.jsonlare attached; the eight repo-level signing secrets are deleted, only thereleaseenv holds them;/trustis verified against 0.51.0, 604ce45ff. Local update signing stays optional, in cmdr-reports#39.)ci-gatejob passed on the real taggh attestation verify … --signer-workflow vdavid/cmdr/.github/workflows/release-pipeline.yml(steps indocs/guides/releasing.md), then move the/trustclaim to SLSA Build Level 3Deploy the api-server first(done 2026-10-06; it also deploys on push now, with D1 migrations first)RELEASE_UPDATE_SIGNING=local; tracked privately in cmdr-reports#39).pkgandCmdr_<version>.intoto.jsonl(Scorecard Signed-Releases then reads 10), and that the CodeQL release gate passed/trust(the profile is published since 2026-10-07; testing needs a real MDM, since macOS refuses a hand-installed PPPC profile) (2026-10-14: done on a real MDM, a self-hosted Fleet on the NAS pushing both published profiles to the enrolled M1, macOS 27.0.1, Cmdr 0.52.0 from its.pkg. Managed preferences read back exactly; TCC granted Full Disk Access from the profile and Cmdr's probe flipped to granted. Gap line dropped from/trust, plan removed, recipe inmanaged_policy/DETAILS.md, 40e7515)docs/security.md) (docs/threat-model.md, linked from/trust. New gaps it found are tracked privately in cmdr-reports#38, all but one fixed.)fuzz/,pnpm check fuzz, plus a slow-checks CI job. They found and fixed three bugs. SMB fuzzing lives insmb2. Not covered yet: SFTP, MTP (mtp-rshas no targets), thumbnails.)Cargo.lock(advisories.yml; runs once the branch is onmain)mtp-rsandsmb2)convert-clip-modelpip deps, dev-only packages with no fix, and Linux-onlyglib. The last one,http-cache-semantics, gets its override once the fix is three days old)scripts/release-ci-gate.sh, run byrelease.shbefore tagging: a fullrun_allCI run on the exact commit must be green, 71e857c; first used for v0.47.0)release.ymltoo (aci-gatejob requires a green fullrun_allCI run on the tagged commit, or its parent for thechore(release)bump)mainfailed in three months. Consider a macOS CI lane (2026-10-06: October is down to 6 of 40 red;docs/notes/ci-health-2026-10.md. Added thedesktop-rust-macoslane, rustdoc inclippy-linux, and pre-push notices and size checks. Making the macOS job required: Make thedesktop-rust-macosCI job required after two weeks of green runs (counting from its first push, 2026-10-XX) #368. Keepingmainitself green: Decrease red CI runs on main #369, someday)/validateanswers, and against the old server it keeps its cached status/validate, so a refunded perpetual license stays active (2026-10-06: approved full refunds and chargebacks revoke viaadjustment.*webhooks; David still needs to subscribe both Paddle destinations toadjustment.createdandadjustment.updated)~/Library/Caches/…/drive-index/, migrating on first launch. Importance and media stay backed up)svelteand@sveltejs/kitare dev dependencies whose code ships in the app. Decide whether to move them or filter the SBOM. (Now built from the bundle itself withrollup-plugin-sbom: it lists exactly the 48 packages that ship.)release-pipeline.yml. The claim moves to Level 3 once the next release verifies, see above.)Data leaving the EU
@getcmdr.commail (includingsecurity@andlegal@) from the Gmail forward to the self-hosted mailcow. Required before the enterprise rollout: no Google dependency. DMARC reports go to Gmail too. (Done 2026-10-06: MX points to self-hosted mailcow (Helsinki), SPFmx -all, DMARC reports todmarc@getcmdr.com; Cloudflare Email Routing is off. All addresses and the catch-all tested from outside. Left for David: remove the Gmail "Send mail as" entry and the SMTP2Go userdavid.getcmdr.)getcmdr.com. Check whether anything still sends through it, then remove the records or add it to the subprocessor list. (Checked 2026-10-05: still in use. Mail fromdavid@getcmdr.comwent out through it on 2026-09-30. Nothing in the code sends through it.) Decided: SMTP2Go stays as mailcow's outbound relay (Hetzner blocks port 25), so add it to the subprocessor list with the mail cutover.MDM deployment
sudorecipe plus the published.mobileconfig, seedocs/specs/mdm-managed-preferences-plan.md§ Testing without an MDM), then wipe the plan (2026-10-14: done on a real MDM, a self-hosted Fleet on the NAS pushing both published profiles to the enrolled M1, macOS 27.0.1, Cmdr 0.52.0 from its.pkg. Managed preferences read back exactly; TCC granted Full Disk Access from the profile and Cmdr's probe flipped to granted. Gap line dropped from/trust, plan removed, recipe inmanaged_policy/DETAILS.md, 40e7515).pkginstaller (2026-10-08: the release pipeline builds, signs, notarizes, and staplesCmdr_<v>_universal.pkgfrom the next release on; Developer ID Installer certificate (G2, expires 2031-09-17) in thereleaseenvironment; renewal steps indocs/guides/releasing.md. A pkg-installed app is root-owned, so the self-updater asks for an admin password; the deploy docs recommendDisableUpdatesvia MDM there)/mdm/cmdr-full-disk-access.mobileconfig, plus the narrower folder permissions; a test pins it to the signing identity)/trust, and remove the matching lines from "Not in place yet" (the managed-preferences part: a "Central management (MDM)" section, sample profile and plist under/mdm/. The.pkgand PPPC lines stay.)No Apple, no Google dependencies
Later: stamps with a real issuing body
CSA STAR Level 1: fill in the CAIQ v4 questionnaire and submit it to the STAR Registry. Afterwards, a vendor questionnaire can be answered with a registry link. (drafts: vdavid/cmdr-reports#45, private. 2026-10-14: the prerequisites are in place. 2026-10-15: the policy is adopted, and the CAIQ stands at 226 Yes, 46 No, 11 N/A. The first submission bounced on a star.watch export bug; resubmitted with our own file.) 2026-10-16: listed at https://cloudsecurityalliance.org/star/registry/rymdskottkarra-ab, linked from
/trust(028a219). It needs a yearly update, with the policy review.OpenChain ISO/IEC 5230 (license compliance) and ISO/IEC 18974 (security assurance) self-certification (drafts: vdavid/cmdr-reports#45, private. 2026-10-14: every policy question answered,
docs/open-source-policy.mdpublished. 2026-10-15: the policy is adopted as v1.0 and the affirmation signed.) 2026-10-16: both checklists answered yes in full and submitted to OpenChain's Community of Conformance, one application per standard;/trustclaims both (84b2961). Renewal every 18 months, next by 2028-04-15 (in the calendar).An accessibility conformance report (VPAT) against WCAG 2.2 AA (2026-10-14: the INT edition, which covers WCAG 2.2, Section 508, and EN 301 549 in one report. Audit done:
docs/notes/accessibility-audit-2026-10.md, gaps in Make the file list speak to VoiceOver: cursor, marked files, position, and file kind #437–Document Cmdr's accessibility features and how to get accessibility help #443 and Check that Cmdr's in-app menus speak under VoiceOver #267. The report page/trust/accessibilityis merged onmain(6be271d; live on the next push). Next: David's VoiceOver run fills the 12 pending rows; guide in the vault,projects/Cmdr/2026-10-14 Cmdr VoiceOver test guide.md) 2026-10-15: David's VoiceOver run passed V1–V12, so every pending row is now Supports (86f5aeb), and each partial row links its open issue (848cf21).an OpenSSF Scorecard badge. The OpenSSF Best Practices badge needs an OSI-approved license, which BSL isn't. (2026-10-06:
scorecard.ymlpublishes, README badge, read-only default tokens. 2026-10-08: score 7.8 after CodeQL (workflows, JS/TS, Rust; release-blocking on high/critical), Docker digest pins, Gradle wrapper validation,osv-scanner.tomlignores with reasons (0 advisories), and amainruleset blocking force-push and deletion. ~8 after the next release adds the provenance file. Code-Review, CII, License, and Branch-Protection stay low by choice)docs(trust): the Full Disk Access and managed-preferences profiles ar…