chore: add LICENSE + SECURITY.md + CONTRIBUTING.md (0.4.58)

OSS hygiene baseline. Three new repo-root files; no source code
touched.

- **LICENSE** (MIT) — declared in package.json since day one but
  the file itself was missing. Required for community-store
  registry submission (#126 Phase H), required by GitHub's "is
  this project licensed?" detection, required by Dependabot's
  license-compatibility check.

- **SECURITY.md** — vulnerability disclosure policy. The plugin
  handles SSH credentials and auto-deploys a remote daemon, so
  the attack surface is non-trivial and a clear "open a private
  Security Advisory, not a public issue" instruction matters.
  Documents the existing cosign verification command (D-δ.2 /
  F24 / #122) and the runtime sha256 verify (D-δ.1 / F23 / #121).

- **CONTRIBUTING.md** — dev setup, branch naming, Conventional
  Commits format (already enforced by commitlint #111), version-
  bump dance, where each kind of decision lives in `docs/`.
  Mirrors the conventions every recent merged PR has followed,
  so the doc captures lived practice rather than aspirational
  rules.

Code of Conduct intentionally omitted at this stage — single-
author repo, will revisit if external contributions accumulate.
README is touched in a separate uncommitted edit (souta is
working on it in the IDE) and stays out of this PR.

Verification:

- All three files render on GitHub's repo-root rendering
  conventions (LICENSE picked up automatically by the
  "License: MIT" header; SECURITY.md surfaces a "Report a
  vulnerability" button; CONTRIBUTING.md surfaces in the PR
  template).
- No code change → no test surface impacted; existing 569 tests
  still green by virtue of not touching anything.

manifest/package/versions bumped 0.4.57 → 0.4.58.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Souta 2026-04-29 10:32:52 +09:00
parent cdc66d27b7
commit b6a5d735d0
7 changed files with 236 additions and 5 deletions

134
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,134 @@
# Contributing
Thanks for your interest. The project is built around a few hard
conventions that make the contribution loop predictable. Please read
this once before opening your first PR.
## Repository layout
```
plugin/ Obsidian plugin (TypeScript, esbuild, vitest)
server/ obsidian-remote-server daemon (Go, fsnotify)
proto/ Shared JSON-RPC method + error definitions (TS + Go in lockstep)
docs/ Architecture notes (shadow vault, perf, testing strategy, …)
deploy/ Turn-key sshd container (Docker compose) for trying the plugin
docker/ Test-only sshd container for the integration suite
```
See [README.md](README.md) for the user-facing story.
## Dev setup
Prerequisites:
- **Node.js 20+** for the plugin (`plugin/package.json`)
- **Go 1.25+** for the daemon (`server/go.mod`'s `go` directive)
- **Docker** for the integration test suite (optional for plugin-only changes)
```bash
# Plugin
cd plugin
npm ci
npm test # ~570 unit tests, ~3 s
npx tsc --noEmit # type-check
npm run dev # esbuild watch into <plugin>/main.js
# Server
cd server
make build # builds bin/obsidian-remote-server (host platform)
make cross # builds 4 platforms into dist/
go test ./...
# Full integration (Docker required)
cd plugin
npm run sshd:start
npm run test:integration
npm run sshd:stop
# Plugin-side perf bench (separate from `test:integration`)
npm run test:integration:bench
```
A working dev vault path can be configured via `REMOTE_SSH_DEV_VAULT`
env var; `npm run build:full` then ships the plugin into that vault.
## Branch + commit convention
### Branches
- `feat/<short-name>` — new feature
- `fix/<short-name>` — bug fix
- `chore/<short-name>` — repo hygiene, dependency bumps, refactors with no user-visible change
- `docs/<short-name>` — documentation-only changes
One branch = one PR = one logical change. We squash-merge from main, so the branch's commits don't need to be pristine — but the PR title and body **do**.
### Commit messages — Conventional Commits, enforced
Format: `type(scope): subject`
```
feat(plugin): Phase D-γ / F18 — error toast taxonomy + Notice / log integration (0.4.51)
fix(server): unbreak Go + Dockerfile after Dependabot rollups (0.4.52)
ci(release): grouped CHANGELOG via git-cliff (0.4.57)
```
- `type``build` `chore` `ci` `docs` `feat` `fix` `perf` `refactor` `revert` `style` `test` `release`
- `scope` is free-form; common scopes: `plugin`, `server`, `proto`, `deploy`, `ci`, `release`, `security`.
- Subject can mix cases (`Phase D-γ` is fine; commitlint's `subject-case` is intentionally relaxed — see [`commitlint.config.mjs`](commitlint.config.mjs)).
- Header cap is **144 characters** (the standard 100 doesn't fit our `Phase X.Y — long subject (0.4.NN)` style).
- The `(0.4.NN)` suffix matches the version bump (see below).
- A trailing `Co-Authored-By:` line is fine; it's stripped from the auto-generated changelog (`cliff.toml` `commit_preprocessors`).
The `commitlint.yml` workflow checks every commit in the PR. A typo in commit #3 of a 5-commit PR fails the gate; please fix in-place + force-push rather than tacking on a `fix typo` commit.
### Version bumps
`plugin/manifest.json`, `plugin/package.json`, and `plugin/versions.json` move together. Use the project's npm `version` script to bump all three at once:
```bash
cd plugin
npm version patch --no-git-tag-version # 0.4.57 → 0.4.58
# (or `minor` / `major` / a literal `0.5.0`)
```
Then commit the four files alongside your code change in a single commit.
`version-check.yml` rejects any PR whose `manifest.json` version isn't strictly greater than the base branch's. If your PR sits open while another bumps main, rebase + bump again.
## Pull request etiquette
- Reuse [`.github/pull_request_template.md`](.github/pull_request_template.md) — the prompts are there for a reason.
- Add a **Test plan** checklist; mark each item once it actually passed locally.
- Run `npx tsc --noEmit -p tsconfig.json` and `npx vitest run` before pushing — CI runs them anyway, but the feedback loop is faster locally.
- For server changes, also run `go test ./...` from `server/`.
- Stack PRs are welcome — open the dependent PR with `--base <prior-branch>`. Once the prior merges, GitHub auto-rebases the dependent PR's base to `main`.
## Where things live
- **Architecture decisions**`docs/architecture-*.md`. The shadow-vault rationale (and why the prior `reconcileFile` route was abandoned) is in `docs/architecture-shadow-vault.md`.
- **Test strategy**`docs/testing-strategy.md`. Phase A (multi-client convergence), B (multi-OS), C (sync-latency + UI reflect) are codified there.
- **Performance numbers** → the `perf-baseline` orphan branch's `baseline.ndjson`, refreshed nightly by `bench.yml`.
- **Issue tracker** → for bug reports, feature requests, design questions.
- **Security issues** → see [SECURITY.md](SECURITY.md), **not** the public issue tracker.
## Code style
- TypeScript: `strictNullChecks: true`, `isolatedModules: true`. No ESLint config required for now (was scoped out as low-value during early development).
- Go: `gofmt -w .` (the `gosec` job in `security.yml` will flag obvious issues).
- Comments: explain **why**, not what. The codebase prefers a few generous block comments at module / class boundaries over per-line noise.
- New tests should mirror the surface they cover: `src/util/Foo.ts``tests/Foo.test.ts`.
## Releases
Tagged releases (`X.Y.Z` format) trigger `.github/workflows/release.yml`:
1. Test gate (typecheck + vitest)
2. Server-binary build × 4 platforms + cosign keyless sign
3. Plugin bundle build + bundle-size check
4. Grouped changelog generated by `git-cliff` (`cliff.toml`)
5. GitHub Release created with all artefacts attached
You don't usually create releases by hand; `release-on-merge.yml` watches main for `manifest.json` version changes and auto-tags.
Thanks again — and welcome.

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Souta Shimozono
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

75
SECURITY.md Normal file
View file

@ -0,0 +1,75 @@
# Security Policy
## Reporting a vulnerability
**Please do not open a public GitHub issue for security bugs.**
This project handles SSH credentials and ships an auto-deployed
remote daemon — the attack surface is non-trivial. Responsible
disclosure helps us patch + release before the issue is public.
To report a vulnerability:
1. Open a **private GitHub Security Advisory** at
<https://github.com/sotashimozono/obsidian-remote-ssh/security/advisories/new>.
2. Include: a minimal reproduction, the affected version, your
suggested severity (low / medium / high / critical), and any
suggested fix or mitigation.
## Response timeline
- **Acknowledgement**: within 7 days.
- **Triage + initial assessment**: within 14 days of acknowledgement.
- **Fix availability** (in main + the next release): depends on
severity and complexity. Critical issues we aim for ≤ 14 days
after triage; lower-severity issues land on the normal release
cadence.
- **Public disclosure**: coordinated with the reporter, typically
after a fixed release ships.
## What's in scope
- The Obsidian plugin code (`plugin/src/**`).
- The Go daemon (`server/**`) running on the user's remote SSH host.
- The shared protocol (`plugin/src/proto/types.ts` ↔
`server/internal/proto/types.go`).
- Release artefacts (signed daemon binaries, plugin bundle).
- CI workflows, especially anything touching `secrets.*`.
## What's out of scope
- Vulnerabilities in upstream dependencies (`ssh2`, `fsnotify`,
Obsidian itself, etc.) — please report those upstream and CC us
if our usage is implicated.
- Configuration mistakes by the operator (e.g. running the daemon
as root, exposing the SSH host on a public IP without auth) —
unless the plugin actively encourages or facilitates the misuse.
- Social-engineering scenarios where the user explicitly accepts a
prompt that surfaces the risk (e.g. trusting a host-key change
in the upcoming `HostKeyMismatchModal` — we surface the diff and
the security implication; the user's choice to trust is theirs).
## Verifying release artefacts
Daemon binaries shipped via GitHub Releases are signed with
[Sigstore cosign](https://www.sigstore.dev/) keyless OIDC against
this repository's GitHub Actions identity. Verify any release
binary independently with:
```bash
cosign verify-blob \
--bundle obsidian-remote-server-linux-amd64.bundle \
--certificate-identity-regexp 'https://github.com/sotashimozono/obsidian-remote-ssh/.github/workflows/release.yml@.*' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
obsidian-remote-server-linux-amd64
```
The plugin's `ServerDeployer` performs a sha256 round-trip
verification on every deploy (`plugin/src/transport/ServerDeployer.ts`
`verifyRemoteSha256`). A mismatch refuses to start the daemon.
## Acknowledgements
We appreciate every responsible disclosure. Reporters are credited
in the security advisory once the issue is publicly disclosed,
unless they prefer to remain anonymous.

View file

@ -1,7 +1,7 @@
{
"id": "remote-ssh",
"name": "Remote SSH",
"version": "0.4.57",
"version": "0.4.58",
"minAppVersion": "1.4.0",
"description": "Edit remote vaults over SSH/SFTP — VS Code Remote SSH for Obsidian",
"author": "",

View file

@ -1,12 +1,12 @@
{
"name": "obsidian-remote-ssh",
"version": "0.4.57",
"version": "0.4.58",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "obsidian-remote-ssh",
"version": "0.4.57",
"version": "0.4.58",
"license": "MIT",
"dependencies": {
"ssh2": "^1.17.0"

View file

@ -1,6 +1,6 @@
{
"name": "obsidian-remote-ssh",
"version": "0.4.57",
"version": "0.4.58",
"description": "VS Code Remote SSH-like experience for Obsidian",
"main": "main.js",
"scripts": {

View file

@ -61,5 +61,6 @@
"0.4.54": "1.4.0",
"0.4.55": "1.4.0",
"0.4.56": "1.4.0",
"0.4.57": "1.4.0"
"0.4.57": "1.4.0",
"0.4.58": "1.4.0"
}