opencode-onboard 0.0.5 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -32
- package/content/{.opencode → .agents}/agents/.bootstrap/AGENTS.template.md +7 -7
- package/content/{.opencode → .agents}/agents/back-engineer.md +27 -26
- package/content/.agents/agents/devops-manager.md +108 -0
- package/content/.agents/agents/front-engineer.md +73 -0
- package/content/.agents/agents/infra-engineer.md +74 -0
- package/content/.agents/agents/quality-engineer.md +74 -0
- package/content/.agents/agents/security-auditor.md +84 -0
- package/content/.opencode/package-lock.json +3 -3
- package/content/AGENTS.md +1 -1
- package/package.json +1 -1
- package/src/index.js +49 -19
- package/src/steps/__tests__/clean-ai-files.test.js +44 -30
- package/src/steps/check-platform.js +2 -2
- package/src/steps/check-rtk.js +1 -1
- package/src/steps/choose-models.js +141 -0
- package/src/steps/choose-skills-provider.js +52 -33
- package/src/steps/clean-ai-files.js +9 -9
- package/src/steps/copy-content.js +1 -1
- package/src/steps/install-browser.js +19 -27
- package/src/utils/__tests__/copy.test.js +0 -22
- package/src/utils/__tests__/exec.test.js +6 -4
- package/src/utils/copy.js +1 -1
- package/src/utils/exec.js +86 -9
- package/src/utils/models-cache.js +101 -0
- package/content/.opencode/agents/.bootstrap/CUSTOM-AGENT.template.md +0 -24
- package/content/.opencode/agents/devops-manager.md +0 -115
- package/content/.opencode/agents/front-engineer.md +0 -73
- package/content/.opencode/agents/infra-engineer.md +0 -73
- package/content/.opencode/agents/quality-engineer.md +0 -75
- package/content/.opencode/agents/security-auditor.md +0 -85
- package/content/.opencode/commands/.gitkeep +0 -0
- package/src/presets/skills-providers.json +0 -14
- package/src/steps/__tests__/choose-team.test.js +0 -105
- /package/content/{.opencode → .agents}/skills/browser-automation/SKILL.md +0 -0
- /package/content/{.opencode → .agents}/skills/ob-userstory-az/SKILL.md +0 -0
- /package/content/{.opencode → .agents}/skills/ob-userstory-gh/SKILL.md +0 -0
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
# Security Auditor
|
|
2
|
-
|
|
3
|
-
> Security specialist, finds vulnerabilities across all layers. Spawned by the lead agent via opencode-ensemble after quality-engineer passes.
|
|
4
|
-
|
|
5
|
-
```
|
|
6
|
-
name: security-auditor
|
|
7
|
-
mode: subagent
|
|
8
|
-
model: explore
|
|
9
|
-
description: |
|
|
10
|
-
Security engineer. Audits completed changes for vulnerabilities.
|
|
11
|
-
OWASP Top 10, secrets exposure, auth gaps, injection risks.
|
|
12
|
-
Receives completed implementation, audits it, reports findings.
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## Domain
|
|
16
|
-
|
|
17
|
-
OWASP Top 10 vulnerabilities, secrets and credential exposure, authentication and authorization gaps, injection risks (SQL, XSS, command), insecure dependencies, misconfigured CORS or headers, data exposure in logs or responses, insecure direct object references. Works across all layers, UI, backend, infra.
|
|
18
|
-
|
|
19
|
-
## RTK, MANDATORY
|
|
20
|
-
|
|
21
|
-
Use `rtk` for ALL CLI commands. Never run commands directly.
|
|
22
|
-
|
|
23
|
-
- `rtk npm audit` NOT `npm audit`
|
|
24
|
-
- `rtk dotnet list package --vulnerable` NOT `dotnet list package --vulnerable`
|
|
25
|
-
|
|
26
|
-
If `rtk` is not available, report it as a blocker. Do not run commands without it.
|
|
27
|
-
|
|
28
|
-
## Skills, Auto-Detection
|
|
29
|
-
|
|
30
|
-
Skills are located in `.opencode/skills/`. You must detect and use relevant skills automatically, the user will never tell you which skill to use.
|
|
31
|
-
|
|
32
|
-
**How to detect:**
|
|
33
|
-
1. Read the task description and identify the domain and platform
|
|
34
|
-
2. Scan `.opencode/skills/` for available skills
|
|
35
|
-
3. Read each `SKILL.md` description to assess relevance
|
|
36
|
-
4. Load and follow any skill that applies, even partial match warrants loading
|
|
37
|
-
|
|
38
|
-
**Rules:**
|
|
39
|
-
- Never implement directly if a skill applies
|
|
40
|
-
- Follow skill instructions exactly, do not partially apply them
|
|
41
|
-
- A skill that is 50% relevant still takes priority over improvising
|
|
42
|
-
- If two skills apply, follow both, resolve conflicts by asking the lead
|
|
43
|
-
|
|
44
|
-
## Responsibilities
|
|
45
|
-
|
|
46
|
-
Audit all changes after quality-engineer signs off:
|
|
47
|
-
- Scan for hardcoded secrets, API keys, passwords, tokens
|
|
48
|
-
- Check `.env` files are gitignored
|
|
49
|
-
- Verify no credentials in logs, URLs, or error responses
|
|
50
|
-
- Check authentication and authorization on sensitive endpoints
|
|
51
|
-
- Verify input validation at system boundaries
|
|
52
|
-
- Check for injection risks in queries and templates
|
|
53
|
-
- Review dependency vulnerabilities
|
|
54
|
-
- Check CORS, headers, and rate limiting
|
|
55
|
-
|
|
56
|
-
## Severity Levels
|
|
57
|
-
|
|
58
|
-
- **Critical**, Must block merge: secret exposure, auth bypass, data loss risk
|
|
59
|
-
- **High**, Should fix before merge: injection risk, missing auth, sensitive data leak
|
|
60
|
-
- **Medium**, Fix soon: missing rate limiting, weak validation, insecure config
|
|
61
|
-
- **Low**, Informational: minor hardening opportunities
|
|
62
|
-
|
|
63
|
-
## Constraints
|
|
64
|
-
|
|
65
|
-
- Audit only, do not implement fixes unless Critical and explicitly asked
|
|
66
|
-
- Do not push to `main`
|
|
67
|
-
- Do not merge PRs, human-only
|
|
68
|
-
- Critical findings must block the PR, report to lead immediately
|
|
69
|
-
|
|
70
|
-
## Output Format
|
|
71
|
-
|
|
72
|
-
```
|
|
73
|
-
## Security Auditor, Done
|
|
74
|
-
|
|
75
|
-
**Status:** pass | blocked
|
|
76
|
-
**Critical:** <count>
|
|
77
|
-
**High:** <count>
|
|
78
|
-
**Medium:** <count>
|
|
79
|
-
**Low:** <count>
|
|
80
|
-
|
|
81
|
-
### Findings
|
|
82
|
-
- [severity] [file:line] <description>, <recommended fix>
|
|
83
|
-
|
|
84
|
-
**Blockers:** none | <critical findings that must be resolved before PR>
|
|
85
|
-
```
|
|
File without changes
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
[
|
|
2
|
-
{
|
|
3
|
-
"label": "ob-skills (default, ships with opencode-onboard)",
|
|
4
|
-
"value": "ob-skills",
|
|
5
|
-
"package": "opencode-onboard",
|
|
6
|
-
"description": "Default skill pack: GitHub and Azure DevOps user stories, pull requests, OpenSpec workflows."
|
|
7
|
-
},
|
|
8
|
-
{
|
|
9
|
-
"label": "None, I will add skills manually",
|
|
10
|
-
"value": "none",
|
|
11
|
-
"package": null,
|
|
12
|
-
"description": "Skip skill installation. Add skills to .opencode/skills/ manually."
|
|
13
|
-
}
|
|
14
|
-
]
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import fse from 'fs-extra'
|
|
2
|
-
import os from 'os'
|
|
3
|
-
import path from 'path'
|
|
4
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
5
|
-
|
|
6
|
-
vi.mock('../../utils/exec.js', () => ({
|
|
7
|
-
header: vi.fn(),
|
|
8
|
-
success: vi.fn(),
|
|
9
|
-
info: vi.fn(),
|
|
10
|
-
}))
|
|
11
|
-
|
|
12
|
-
vi.mock('@inquirer/prompts', () => ({
|
|
13
|
-
checkbox: vi.fn(),
|
|
14
|
-
input: vi.fn(),
|
|
15
|
-
}))
|
|
16
|
-
|
|
17
|
-
import { checkbox, input } from '@inquirer/prompts'
|
|
18
|
-
import { info } from '../../utils/exec.js'
|
|
19
|
-
|
|
20
|
-
describe('chooseTeam()', () => {
|
|
21
|
-
let tmpDir
|
|
22
|
-
let originalCwd
|
|
23
|
-
|
|
24
|
-
beforeEach(async () => {
|
|
25
|
-
tmpDir = await fse.mkdtemp(path.join(os.tmpdir(), 'ob-team-test-'))
|
|
26
|
-
originalCwd = process.cwd()
|
|
27
|
-
process.chdir(tmpDir)
|
|
28
|
-
vi.clearAllMocks()
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
afterEach(async () => {
|
|
32
|
-
process.chdir(originalCwd)
|
|
33
|
-
await fse.remove(tmpDir)
|
|
34
|
-
vi.resetModules()
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
it('returns empty array and skips when no agents selected', async () => {
|
|
38
|
-
checkbox.mockResolvedValue([])
|
|
39
|
-
// single empty input to exit the custom loop
|
|
40
|
-
input.mockResolvedValue('')
|
|
41
|
-
|
|
42
|
-
// Dynamic import so process.cwd() is captured at call time
|
|
43
|
-
const { chooseTeam } = await import('../choose-team.js')
|
|
44
|
-
const result = await chooseTeam()
|
|
45
|
-
|
|
46
|
-
expect(result).toEqual([])
|
|
47
|
-
expect(info).toHaveBeenCalledWith('No agents selected, skipping team setup.')
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
it('creates agent files for selected preset agents', async () => {
|
|
51
|
-
checkbox.mockResolvedValue(['frontend', 'backend'])
|
|
52
|
-
input.mockResolvedValue('') // no custom agents
|
|
53
|
-
|
|
54
|
-
const { chooseTeam } = await import('../choose-team.js')
|
|
55
|
-
const result = await chooseTeam()
|
|
56
|
-
|
|
57
|
-
expect(result).toEqual(['frontend', 'backend'])
|
|
58
|
-
|
|
59
|
-
const frontendPath = path.join(tmpDir, '.opencode', 'agents', 'frontend.md')
|
|
60
|
-
const backendPath = path.join(tmpDir, '.opencode', 'agents', 'backend.md')
|
|
61
|
-
expect(await fse.pathExists(frontendPath)).toBe(true)
|
|
62
|
-
expect(await fse.pathExists(backendPath)).toBe(true)
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
it('creates agent file for custom agent name', async () => {
|
|
66
|
-
checkbox.mockResolvedValue([])
|
|
67
|
-
input.mockResolvedValueOnce('devops').mockResolvedValueOnce('') // one custom, then stop
|
|
68
|
-
|
|
69
|
-
const { chooseTeam } = await import('../choose-team.js')
|
|
70
|
-
const result = await chooseTeam()
|
|
71
|
-
|
|
72
|
-
expect(result).toContain('devops')
|
|
73
|
-
const devopsPath = path.join(tmpDir, '.opencode', 'agents', 'devops.md')
|
|
74
|
-
expect(await fse.pathExists(devopsPath)).toBe(true)
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
it('normalises custom agent name (lowercase, spaces to dashes)', async () => {
|
|
78
|
-
checkbox.mockResolvedValue([])
|
|
79
|
-
input.mockResolvedValueOnce('My Agent').mockResolvedValueOnce('')
|
|
80
|
-
|
|
81
|
-
const { chooseTeam } = await import('../choose-team.js')
|
|
82
|
-
const result = await chooseTeam()
|
|
83
|
-
|
|
84
|
-
expect(result).toContain('my-agent')
|
|
85
|
-
const agentPath = path.join(tmpDir, '.opencode', 'agents', 'my-agent.md')
|
|
86
|
-
expect(await fse.pathExists(agentPath)).toBe(true)
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
it('skips agent file creation if it already exists', async () => {
|
|
90
|
-
checkbox.mockResolvedValue(['frontend'])
|
|
91
|
-
input.mockResolvedValue('')
|
|
92
|
-
|
|
93
|
-
const agentsDir = path.join(tmpDir, '.opencode', 'agents')
|
|
94
|
-
await fse.ensureDir(agentsDir)
|
|
95
|
-
await fse.writeFile(path.join(agentsDir, 'frontend.md'), 'existing content')
|
|
96
|
-
|
|
97
|
-
const { chooseTeam } = await import('../choose-team.js')
|
|
98
|
-
await chooseTeam()
|
|
99
|
-
|
|
100
|
-
// File should still have original content (not overwritten)
|
|
101
|
-
const content = await fse.readFile(path.join(agentsDir, 'frontend.md'), 'utf-8')
|
|
102
|
-
expect(content).toBe('existing content')
|
|
103
|
-
expect(info).toHaveBeenCalledWith('frontend.md already exists, skipping')
|
|
104
|
-
})
|
|
105
|
-
})
|
|
File without changes
|
|
File without changes
|
|
File without changes
|