oasis-implementation-patterns
GitHub提供OASIS项目的代码实现规范,指导如何按模块修改CLI、分析器、LangGraph智能体、缓存及仪表盘等行为,确保代码组织一致性和逻辑复用。
Trigger Scenarios
Install
npx skills add psyray/oasis --skill oasis-implementation-patterns -g -y
SKILL.md
Frontmatter
{
"name": "oasis-implementation-patterns",
"description": "Implement OASIS features with patterns used in commit history. Use when modifying scanner flow, analysis, LangGraph agent (`oasis\/agent\/`), model integration, caching, CLI flags, or dashboard behavior."
}
OASIS Implementation Patterns
Goal
Apply the code organization and delivery style repeatedly used in OASIS commits.
Workflow
- Classify the change as
feat,fix, orrefactor. - Identify the bounded module(s) to touch instead of editing a single large file:
oasis/oasis.py: CLI and orchestrationoasis/analyze.py:SecurityAnalyzer— structured outputs, embedding, cache, and LangGraph hook methods (langgraph_discover_and_publish,langgraph_scan_and_publish, etc.) invoked by the agent layeroasis/agent/: LangGraph-only — compile the DAG, state schema, node wrappers, andinvoke_oasis_langgraph(canonical pipeline entry). Keep graph structure and stable node names in one place (see LangGraph layout below).oasis/schemas/: Pydantic models for LLM JSON and canonical vulnerability reportsoasis/report.py: JSON-first vulnerability reports; Jinja underoasis/templates/reports/oasis/web.py: dashboard indexing (json/stats), APIs (/api/report-json,/api/progress, Socket.IOscan_progress, legacy MD preview rules)oasis/ollama_manager.py: model and Ollama interactionsoasis/helpers/: all shared helpers (formatting, parsing, progress helpers, small pure utilities). Do not leave helper-shaped functions in feature modules—extract them here and group by category in dedicated modules (see Design Guardrails).oasis/helpers/embed_models.py: canonical embed-model normalization/parsing; reuse it for CLI parsing and embedding-manager primary model resolution.oasis/static/js/dashboard/*: web dashboard behavior (JSON modal preview,force=1on reload for stats/reports/progress,applyProgressPayload/progressState)
- Keep interfaces compatible unless migration is explicit.
- Update docs (
README.md) when user-facing flags or behavior change.- Keep
README.mdFeaturesas summary-only bullets. - Put detailed behavior/usage in the existing relevant section; create a new section when a new feature has no fitting section.
- Keep
- Prefer defensive handling around cache/model/network boundaries.
- For reporting changes, treat canonical JSON schema as the source of truth and keep Jinja templates synchronized.
- Before considering the task done: verify no duplicated logic remains (same rule in two places, mirrored constants, near-copy functions). Refactor into a single canonical implementation and import it everywhere it is needed.
Dashboard report modals (shared architecture)
When changing any report preview inside #report-modal (vulnerability, executive summary, audit report, future canonical types), follow the single architecture described in .cursor/rules/oasis-dashboard-js-patterns.mdc (Report modal architecture):
- Compact layout + TOC / section jumps + optional Chart.js blocks, scoped CSS in
report_preview.cssunder#report-modal-content. - One post-render initializer path from
modal.js(_finalizeReportModalView) for kind detection (stem, path, orreport_type) — no scattered one-off branches. - Assistant: one
mountReportAssistantPanelpipeline with variants (finding selectors only for vuln JSON; aggregated or report-scoped chat for executive/audit as designed) — duplicate chat stacks per report type are not acceptable. - Server: meta/preview endpoints and parsing live in
web.py+oasis/helpers/; extend shared helpers instead of copying aggregation logic for each modal.
Treat audit modal work as reusing this spine when aligning with the vulnerability/executive experience, not as a greenfield duplicate UI stack.
LangGraph layout (canonical analysis pipeline)
- Product path:
AnalysisType.GRAPHinoasis/enums.pyis the only orchestration mode; on-disk chunk caches live undergraph/deepandgraph/scan(seeoasis/cache.py). - Import discipline: Import LangGraph entry points explicitly (e.g.
from oasis.agent.invoke import invoke_oasis_langgraph). Theoasis.agentpackage docstring explains avoiding a heavy import at interpreter startup when only the submodule is needed. oasis/agent/graph_labels.py: Single source for node ids (GRAPH_NODE_*) and conditional route targets — use these strings ingraph.py, routing, and tests instead of scattering literals.oasis/agent/graph.py: BuildsStateGraph(OasisGraphState)— edges: Discover → Scan → Expand → Deep → Verify → (conditional: Expand or Report) → (conditional: PoC or END when PoC disabled) → END.oasis/agent/tools.py: Thin dispatch — each node calls the matchingSecurityAnalyzer.langgraph_*method; console UX usesoasis/helpers/langgraph_console.py(langgraph_emit,langgraph_emit_phase, etc.).oasis/agent/state.py: Typed state passed between nodes (all_results,expand_iterations,max_expand_iterationsfrom CLI, PoC markdown accumulator, etc.).- Helpers tied to the graph:
oasis/helpers/graph_progress.py— executive-summaryphasesrows aligned with LangGraph stages (ProgressPhaseRowId.GRAPH_*,ProgressActivePhase.GRAPH_PIPELINE).oasis/helpers/langgraph_counts.py— canonical vuln-type totals for LangGraph (embedding_tasks_vuln_types_total,deep_payload_vuln_types_total).oasis/helpers/langgraph_console.py— numbered phases, tqdm-safe logging, post-pipeline / report-delivery banners (also used fromreport.py).oasis/helpers/scan_progress_md.py— normalize scan progress JSON / markdown sections (keep in sync with report-side progress).oasis/helpers/context/expand.py— pure line-window expansion around suspicious spans; defaults fromoasis/config.py(CONTEXT_EXPAND_*).oasis/helpers/poc_digest.py— compact findings digest JSON for--poc-assist.oasis/helpers/poc_pipeline.py— PoC budgets (re-export from config), hints markdown (build_poc_hints_markdown), chat options (poc_assist_chat_options), stage DEBUG logging (maybe_debug_log_poc_stage_output).
- CLI (extend
README.mdwhen behavior changes):--langgraph-max-expand(langgraph_max_expand_iterations),--poc-hints,--poc-assist. - Tests:
tests/test_analyze_orchestration.pyfor the LangGraph pipeline and PoC helpers;tests/test_oasis_cli.pyfor LangGraph-related flags.
Design Guardrails
Incremental scan progress (see Cursor rules)
Details live in .cursor/rules/oasis-python-architecture.mdc (constants in oasis/helpers/progress/__init__.py, sidecar, helper modules) and .cursor/rules/oasis-dashboard-js-patterns.mdc (REST, Socket.IO, stale updated_at guard). Touch oasis/helpers/progress/__init__.py, report.py, web.py, and dashboard JS together when the wire contract changes; extend tests/test_report_schema.py when behavior is contract-visible.
Audit metrics and dashboard comparison
Report.generate_audit_reportmust keep anAudit Metrics Summarymarkdown table with stableMetric | Valuerows (count/similarity/high-medium-low tiers).- When
jsonis in output formats, OASIS also writesaudit_report.json(oasis/schemas/audit_report.py); Markdown and JSON must reflect the same document. The dashboard prefers sibling JSON for listing metrics and modal HTML via/api/report-htmlwhen the file exists. WebServerparses metrics intoaudit_metricsfor/api/reports(JSON first, then Markdown). Sharedmd→jsonrules live inoasis/helpers/dashboard/json_sibling.pyand dashboardaudit-report-paths.js—keep them aligned withweb.pypreview routes.- Dashboard comparison UI (
utils.js+views.js+interactions.js) depends on those keys; treat report/web/dashboard as one contract surface and update tests intests/test_report_schema.pytogether.
Report storage, executive JSON, and dashboard filters
- Output tree: Default
security_reports/<project_slug>/YYYYMMDD_HHMMSS/…; optional--project-name/-pnoverrides slug naming—coordinateoasis/helpers/report_project.py, CLI (oasis/oasis.py), exporters, andREADME.mdwhen behavior shifts. - Executive summary canonical JSON: Rich
schema_versiondocument built inoasis/helpers/executive_summary.pyandoasis/report.py(overview KPIs,guidance_markdown,tier_definitions, cappedsimilarity_highlights). HTML preview usesexecutive_summary_from_json.html.j2andexecutive-preview.js(TOC, Chart.js)—change schema, templates, and dashboard consumers together. analysis_root: Stored relative tosecurity_reports/in new JSON; resolution lives inoasis/helpers/analysis_root_path.py—reuse for assistant/RAG andscan_root; never duplicate path guessing inweb.py.- Dashboard: Severity (tier) + project filters and scoped previews (queries wrapped with active filters; server rejects out-of-scope paths).
/api/statsexposesseverity_finding_totals. Python:oasis/helpers/dashboard/severity_filter.pyandweb.py; JS:filters.js,api.js,modal.js. - Web UI theme: Header light/dark toggle and
oasis:theme-changeinbootstrap.js; charts must follow (views.js,executive-preview.js).
Duplication and centralization (strict)
- Do not repeat code. Treat copy-paste and “almost the same” branches as defects: merge into one function, module, or schema and reuse. KISS means the smallest correct change, not duplicating logic to save a refactor step. DRY is mandatory, not aspirational. SOLID is incompatible with parallel implementations of the same rule in different files.
- Before shipping, ask: “If this behavior changes tomorrow, is there exactly one place to edit?” If not, centralize first (Python:
oasis/helpers/oroasis/schemas/as appropriate; JS dashboard: shared modules underoasis/static/js/dashboard/). - Duplicating strings, field names, validation rules, or API shapes across modules is still duplication—use shared constants, Pydantic models, or helpers.
Finding-validation pipeline (POST /api/assistant/investigate)
When changing how the assistant validates findings, follow the contract locked in the canonical plan (.cursor/plans/validation-vulnerability-validation.plan.md):
- Sink resolution lives in one helper:
oasis/helpers/assistant/web/sink_resolution.py(resolve_sink_from_finding_indices+coerce_positive_int_line). It handles primary payloads (vulnerability JSON with afilesarray) and scope payloads fromfinding_scope_report_path(executive aggregate flow), plus integral-floatsink_lineclients. Do not re-implement this lookup inline inweb.pyor other callers. - Executive aggregate flow:
assistant_investigatemust runfinding_scope_report_paththroughoasis.helpers.executive.assistant_scope.resolve_aggregate_finding_scope_payloadbefore mapping indices, mirroring whatassistant_chatalready does for the chat panel — same pure helper, same security guardrails (model-dir match, traversal protection). - Verdict honesty:
compute_verdictruns on the full deterministic evidence (oasis/helpers/assistant/verdict/verdict.py). Never mutatestatus,confidence,summary, orfamilybased on presentation tweaks; if evidence is thin,insufficient_signalis the correct outcome. - Presentation-time EP filter: After
compute_verdict, callapply_presentation_filter_to_result(oasis/helpers/assistant/web/result_presentation.py) to pruneentry_pointsand rebuildcitations:flow: keep EPs linked by anexecution_paths.entry_pointif any, else EPs whose citation file matchesscope.sink_file, else empty.access: keep only EPs whose citation file matchesscope.sink_file; never filtercontrol_checks/authz_hits.config: untouched (no EPs).
- LLM synthesis anchoring:
compact_investigation_for_llm(oasis/helpers/assistant/think/investigation_synth.py) places ascope_focusblock (vuln name, family, sink_file/line, verdict status/confidence) at the head of the dump; the system prompt explicitly references it and forbids fabricating paths or chains. When changing this contract, keep prompt + payload in sync. - Tests: helper unit tests in
tests/test_assistant_validation.py(TestSinkResolution,TestPresentationFilter,TestScopeFocusInLLMPayload) and route end-to-end intests/test_web_assistant_api.py(TestAssistantInvestigateRoute). Same change set when behavior shifts; verdict-label assertions must stay deterministic.
Other guardrails
- Use KISS: choose the smallest change that solves the issue after consolidation, not instead of it.
- Helper centralization: Anything that matches “helper” characteristics—stateless or lightly stateful utilities, shared formatters/parsers, progress or status row builders, guards, small transforms reused outside one call site—must be implemented under
oasis/helpers/, in a module that matches its category (e.g. progress-related code besidescan_progress.py/exec_summary_progress.py, shared types besideprogress_types.py). When touching existing code, relocate qualifying functions into the appropriate helper module instead of growing orchestration files. - Use SOLID: isolate responsibilities and avoid growing god functions; helpers stay thin and focused per module.
- Keep UX fixes localized for dashboard modules and templates.
Done Criteria
- Run the relevant
tests/test_<area>.pymodule(s) (orunittest discover -s tests) for code you changed; add or extend tests in the file that matches the subsystem (same layout as in the project: report contract, CLI, cache, embedding, helpers, web, LangGraph orchestration intests/test_analyze_orchestration.py, etc.). - No new duplicated logic (including near-duplicates); consolidation is part of the task, not optional follow-up.
- No obvious module boundary violation; no new helper-shaped logic left outside
oasis/helpers/without a strong, documented reason. - Any CLI option change is documented.
- Structured output/report changes stay aligned across
oasis/schemas/,oasis/report.py,oasis/templates/reports/, andtests/test_report_schema.py. - Incremental progress contract changes stay aligned across
oasis/helpers/progress/__init__.py,report.py,web.py, dashboard JS, and contract tests when applicable (same spirit as report schema alignment). - Change intent can be summarized with a conventional commit subject.
Version History
- 60388ad Current 2026-08-16 15:44


