Skip to content

Commit ac41436

Browse files
mrhpythonMichael
andauthored
ci: ESLint + /chat smoke test (#6)
* ci: add tag-based Docker release to GHCR * ci: extend release workflow to create GitHub Release with notes * docs: add CONTRIBUTING and SECURITY policies * ci: add ESLint (npx) and /chat smoke test; wire into CI * chore(ci): trigger checks for PR #6 --------- Co-authored-by: Michael <michael@localhost>
1 parent 1cfe77d commit ac41436

7 files changed

Lines changed: 153 additions & 1 deletion

File tree

.eslintignore

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
node_modules/
2+
archive/
3+
receipts/
4+
workspace/
5+
**/.agent-os/**
6+
**/.venv/**
7+
**/__pycache__/**
8+

.eslintrc.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"root": true,
3+
"env": { "es2021": true, "node": true },
4+
"parserOptions": { "ecmaVersion": 2021 },
5+
"extends": ["eslint:recommended"],
6+
"ignorePatterns": [
7+
"node_modules/**",
8+
"archive/**",
9+
"receipts/**",
10+
"workspace/**",
11+
"**/.agent-os/**",
12+
"**/.venv/**",
13+
"**/__pycache__/**"
14+
],
15+
"overrides": [
16+
{
17+
"files": ["backend/**/*.cjs", "tools/**/*.cjs"],
18+
"rules": {
19+
"no-undef": "off",
20+
"no-unused-vars": ["warn", { "args": "none", "ignoreRestSiblings": true }],
21+
"no-console": "off"
22+
}
23+
}
24+
]
25+
}
26+

.github/workflows/ci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ jobs:
2727
sleep 1
2828
curl -fsS http://127.0.0.1:8790/health | tee health.json
2929
kill $(cat api.pid)
30+
- name: Run ESLint (npx)
31+
run: npx -y eslint .
3032
- name: Lint (if present)
3133
run: npm run -s lint --if-present
3234
- name: Test (if present)

CONTRIBUTING.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
Contributing to Soulfield
2+
3+
Thanks for helping improve Soulfield! This guide keeps contributions smooth and predictable.
4+
5+
Basics
6+
- Use feature branches from `main`; open PRs early as draft when helpful.
7+
- Keep PRs focused and small; include a clear title and summary.
8+
- Prefer tests or a quick manual validation plan in the PR.
9+
10+
Development
11+
- Node: `npm ci && DEV_NO_API=1 npm start` then hit `GET /health`.
12+
- MCP (read‑only FS): `npm run start:mcp` then `GET /mcp/tools`.
13+
- Python (optional): run `pytest` for FastAPI sanity tests.
14+
15+
Coding Standards
16+
- JS/Node: follow existing patterns; keep changes minimal and explicit.
17+
- Python: prefer pytest for tests; descriptive names; no one‑letter vars.
18+
- Avoid unrelated refactors in the same PR; call them out if necessary.
19+
20+
CI & Checks
21+
- CI runs Node and Python jobs; both must be green.
22+
- New workflows should be minimal and secure by default.
23+
24+
Commit & PR Hygiene
25+
- Conventional style (suggested):
26+
- feat:, fix:, chore:, docs:, ci:, test:, refactor:
27+
- PR template: fill Summary, Checklist, and Validation steps.
28+
29+
Security
30+
- Never commit secrets. `.env` is ignored; use `.env.example` for docs.
31+
- MCP is read‑only and hardened, but treat it as a potential disclosure surface.
32+
- See SECURITY.md for reporting vulnerabilities.
33+
34+
Release
35+
- Tag `vX.Y.Z` on main to trigger Docker image publish and a GitHub Release.
36+

SECURITY.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Security Policy
2+
3+
Supported Versions
4+
- Active development on `main`. Releases are tagged `vX.Y.Z`.
5+
6+
Reporting a Vulnerability
7+
- Please report security issues privately via GitHub Security Advisories:
8+
- Go to the repository’s “Security” tab → “Advisories” → “Report a vulnerability”.
9+
- If that’s unavailable, email the maintainer or open a minimal issue requesting a private channel.
10+
11+
Do not disclose publicly until a fix is available and coordinated.
12+
13+
Handling & Disclosure
14+
- We will acknowledge reports within 72 hours.
15+
- We aim to provide a fix or mitigation and publish a patch release.
16+
- After a fix is released, we’ll coordinate a responsible disclosure timeline.
17+
18+
Secrets & Hardening
19+
- `.env` and `.env.*` are ignored by git; do not commit secrets.
20+
- The MCP server is read‑only and blocks `.env*`, `.git`, `.ssh`, and `receipts/` paths.
21+
- Avoid logging sensitive values; use environment variables for API keys.
22+

backend/tests/chat-smoke.cjs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#!/usr/bin/env node
2+
/* Simple smoke test for /chat using DEV_NO_API=1 (offline). */
3+
const cp = require('child_process');
4+
const fetch = require('node-fetch');
5+
6+
const PORT = 8790;
7+
8+
function sleep(ms){ return new Promise(r=>setTimeout(r, ms)); }
9+
10+
async function waitForHealth(timeoutMs=5000){
11+
const deadline = Date.now() + timeoutMs;
12+
while (Date.now() < deadline){
13+
try {
14+
const r = await fetch(`http://127.0.0.1:${PORT}/health`);
15+
if (r.ok) return true;
16+
} catch {}
17+
await sleep(150);
18+
}
19+
return false;
20+
}
21+
22+
(async () => {
23+
const child = cp.spawn(process.execPath, ['backend/index.cjs'], {
24+
env: { ...process.env, DEV_NO_API: '1', PORT: String(PORT) },
25+
stdio: 'ignore'
26+
});
27+
28+
try {
29+
const ok = await waitForHealth(6000);
30+
if (!ok) throw new Error('API did not become healthy');
31+
32+
// !help path
33+
const helpRes = await fetch(`http://127.0.0.1:${PORT}/chat`, {
34+
method: 'POST', headers: { 'content-type': 'application/json' },
35+
body: JSON.stringify({ prompt: '!help' })
36+
});
37+
if (!helpRes.ok) throw new Error('!help request failed');
38+
const helpJson = await helpRes.json();
39+
if (!helpJson.output || typeof helpJson.output !== 'string') throw new Error('!help output missing');
40+
41+
// @aiden path
42+
const aidenRes = await fetch(`http://127.0.0.1:${PORT}/chat`, {
43+
method: 'POST', headers: { 'content-type': 'application/json' },
44+
body: JSON.stringify({ prompt: '@aiden: ping' })
45+
});
46+
if (!aidenRes.ok) throw new Error('@aiden request failed');
47+
const aidenJson = await aidenRes.json();
48+
if (!aidenJson.output || typeof aidenJson.output !== 'string') throw new Error('@aiden output missing');
49+
50+
process.exit(0);
51+
} catch (e){
52+
console.error(String(e && e.message || e));
53+
process.exit(1);
54+
} finally {
55+
child.kill('SIGTERM');
56+
}
57+
})();
58+

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"start:tui": "node backend/tui.js",
99
"test:apply": "node backend/tests/test-apply.js --dry",
1010
"test:apply:run": "node backend/tests/test-apply.js --apply",
11-
"test": "echo \"No unit tests; try npm run test:apply\" && exit 0"
11+
"test": "node backend/tests/chat-smoke.cjs"
1212
},
1313
"keywords": [],
1414
"author": "",

0 commit comments

Comments
 (0)