feat(harness): add readonly mysql tool
This commit is contained in:
@@ -38,3 +38,4 @@
|
||||
| 2026-06-23 | phase1-infrastructure | 搭建第一阶段基础设施,包括 MySQL、Redis、Milvus、Flyway 和 JPA。 | 基础设施/文档管理 | MySQL, Redis, Milvus, Flyway, JPA, 向量检索, 类别过滤 | - | archived |
|
||||
| 2026-05-29 | chatmodel-abstraction | 抽象 ChatModel 和 EmbeddingModel,支持多模型路由。 | 解耦/多模型路由 | ChatModel, EmbeddingModel, DeepSeek, BGE-M3, SiliconFlow, Spring AI | - | archived |
|
||||
| 2026-07-21 | single-react-rag-log-projections | RAG/log projection adapters through ToolBoundary | Harness/Tool projection | ISS-014, RAG, query_logs, projection, scope, redaction, MOCK, NO_EVIDENCE | openspec/changes/archive/2026-07-21-single-react-rag-log-projections | archived |
|
||||
| 2026-07-21 | single-react-mysql-readonly-tool | Fail-closed read-only MySQL evidence Tool with AST allowlist, JDBC controls and bounded projection | Harness/MySQL security | ISS-014, MySQL, JSqlParser, allowlist, PreparedStatement, timeout, projection | openspec/changes/archive/2026-07-21-single-react-mysql-readonly-tool | archived |
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
# Acceptance: single-react-mysql-readonly-tool
|
||||
|
||||
## Commit preflight
|
||||
|
||||
- OpenSpec strict validation: passed.
|
||||
- Scope: fail-closed SQL validator, exact allowlist, JDBC read-only executor, bounded MySQL projection, ToolBoundary adapter and query-script safety cleanup.
|
||||
- Non-goals: public Agent/Chat cutover, metadata discovery, Agent persistence database access, dynamic/tenant authorization and live production datasource provisioning.
|
||||
- Security prerequisite: script write branch/default external connection values are explicitly included in this change.
|
||||
|
||||
## Apply acceptance
|
||||
|
||||
- Implemented and verified.
|
||||
- Static, Maven and script evidence is recorded in `evidence.md`.
|
||||
- No browser/manual verification applies; this stage adds no UI or public protocol change.
|
||||
- Residual risk is limited to later live datasource provisioning/driver behavior and stage 4 integration.
|
||||
|
||||
## Archive acceptance
|
||||
|
||||
- All OpenSpec tasks are complete.
|
||||
- `.archive-ready` marker is created after focused verification.
|
||||
- OpenSpec is ready to move to the dated archive directory.
|
||||
- Archive completed at `openspec/changes/archive/2026-07-21-single-react-mysql-readonly-tool`.
|
||||
|
||||
## Remaining work
|
||||
|
||||
- Stage 4 Diagnosis Agent integration and later live datasource/driver E2E remain outside this archive.
|
||||
@@ -0,0 +1,26 @@
|
||||
# Brief: single-react-mysql-readonly-tool
|
||||
|
||||
## Background
|
||||
|
||||
阶段 3A 提供了统一 ToolBoundary 和 canonical invocation store,阶段 3B 提供了 RAG/日志投影。3C 需要独立实现安全敏感的只读 MySQL Tool,避免 Agent 生成的 SQL 直接进入数据库。
|
||||
|
||||
## Goals
|
||||
|
||||
- 使用 JSqlParser 对保守 SELECT 子集进行 fail-closed AST 校验。
|
||||
- 使用逻辑数据源和 schema/table/column 精确 allowlist 授权。
|
||||
- 使用参数绑定、只读 JDBC、超时、取消和结果预算。
|
||||
- 通过阶段 3A boundary 投影为冻结的 `MysqlToolResult`。
|
||||
- 清理查询脚本的写入分支和默认连接风险。
|
||||
|
||||
## Non-goals
|
||||
|
||||
- 不接入公开 Agent/Chat 入口。
|
||||
- 不提供元数据发现、动态授权、租户/行级权限或生产 datasource provisioning。
|
||||
- 不查询 Agent 自身持久化数据库。
|
||||
|
||||
## Classification
|
||||
|
||||
- Scale: complex
|
||||
- Interface impact: L2 internal Harness tool/adapter, plus build dependency and script safety behavior
|
||||
- Issue: ISS-014 stage 3C
|
||||
- Change slug: `single-react-mysql-readonly-tool`
|
||||
@@ -0,0 +1,108 @@
|
||||
# Decisions: single-react-mysql-readonly-tool
|
||||
|
||||
## Discover status
|
||||
|
||||
- Checkpoint: Discover
|
||||
- Capability source: `sm-flow` with local ISS-014, OpenSpec contracts, existing JDBC dependency/configuration and JSqlParser 4.6 already present in the local Maven cache.
|
||||
- Scale: complex, because this stage combines AST policy, authorization, JDBC resource limits, projection, and security cleanup.
|
||||
|
||||
## Evidence-driven findings
|
||||
|
||||
1. `MysqlToolRequest` and `MysqlToolResult` are already frozen under `harness.tool.contract`; no public DTO change is needed.
|
||||
2. The project already has MySQL JDBC/JPA dependencies, but no Agent-facing external read-only executor or SQL policy.
|
||||
3. JSqlParser 4.6 is available in the local Maven cache and exposes `CCJSqlParserUtil`, `Select`, `PlainSelect`, `Table`, `Column`, `Function`, `JdbcParameter` and visitor adapters compatible with Java 17.
|
||||
4. The current application datasource points to the Agent persistence database; the new Tool must use an independently configured logical datasource map and must not reuse that datasource implicitly.
|
||||
5. `scripts/query_mysql.py` currently defaults host/port/user values and contains a non-SELECT commit branch. This violates the ISS-014 security prerequisite and will be changed to read-only, environment-only behavior.
|
||||
|
||||
## Question pool
|
||||
|
||||
| Dimension | Question | Mode | Conclusion | Status |
|
||||
|---|---|---|---|---|
|
||||
| SQL language | Which SQL subset is executable? | evidence-driven | One SELECT, explicit columns, INNER/LEFT JOIN, predicates/group/order, parameter placeholders and allowlisted aggregates. | resolved |
|
||||
| Security | How is authorization decided? | evidence-driven | Independent exact schema/table/column allowlist; parser acceptance alone is insufficient. | resolved |
|
||||
| Data source | Can the Agent pass JDBC coordinates? | evidence-driven | No. Only logical data_source IDs are accepted; connection properties remain configuration/Secret data. | resolved |
|
||||
| Execution | Which JDBC controls are mandatory? | evidence-driven | PreparedStatement, readOnly connection, setMaxRows, query timeout and Run cancellation. | resolved |
|
||||
| Metadata | Can the Tool discover tables/columns? | evidence-driven | No. SHOW/DESCRIBE/information_schema are rejected. | resolved |
|
||||
| Compatibility | Does this cut over public runtime now? | evidence-driven | No. Add internal adapter/executor; Diagnosis Agent integration is stage 4. | resolved |
|
||||
|
||||
## User-confirmed direction
|
||||
|
||||
- Use the frozen `MysqlToolRequest`/`MysqlToolResult` contract.
|
||||
- Reuse the existing ToolBoundary and canonical invocation store.
|
||||
- Keep stage boundaries serial: archive and commit 3C before stage 4.
|
||||
- Do not pause for routine apply/archive/commit confirmation.
|
||||
|
||||
## Pre-apply research
|
||||
|
||||
### Existing implementations and dependencies
|
||||
|
||||
- `src/main/java/com/superbiz/agent/harness/tool/contract/MysqlToolRequest.java`
|
||||
- `src/main/java/com/superbiz/agent/harness/tool/contract/MysqlToolResult.java`
|
||||
- `src/main/java/com/superbiz/agent/harness/tool/boundary/ToolBoundary.java`
|
||||
- `src/main/java/com/superbiz/agent/harness/tool/adapter/QueryLogsToolAdapter.java`
|
||||
- `src/main/resources/application.yml`
|
||||
- `pom.xml` (`mysql-connector-j` already present; add JSqlParser 4.6)
|
||||
- `scripts/query_mysql.py`
|
||||
|
||||
### New classes
|
||||
|
||||
- `MysqlToolLimits`
|
||||
- `MysqlDataSourceDefinition` / allowlist value objects
|
||||
- `MysqlQueryPlan`
|
||||
- `MysqlSqlValidator`
|
||||
- `MysqlReadOnlyExecutor` and JDBC implementation
|
||||
- `MysqlResultProjector`
|
||||
- `MysqlToolAdapter`
|
||||
|
||||
### Risk controls
|
||||
|
||||
- Do not create a generic plugin/DSL layer.
|
||||
- Do not use regex or `startsWith` as SQL authorization.
|
||||
- Fail closed on parser/visitor uncertainty.
|
||||
- Keep raw result canonical-only and expose only bounded projection.
|
||||
|
||||
## Commit checkpoint preparation
|
||||
|
||||
- Proposal scope, design choices, frozen SQL subset, security script cleanup and acceptance scenarios are ready for Commit artifact generation.
|
||||
|
||||
## Commit audit
|
||||
|
||||
- Capability source: `sm-flow` and local OpenSpec CLI.
|
||||
- OpenSpec strict validation: passed for `single-react-mysql-readonly-tool`.
|
||||
- Cross-artifact alignment:
|
||||
- brief goals/non-goals -> proposal scope: aligned.
|
||||
- proposal SQL/security boundaries -> design architecture: aligned.
|
||||
- design validator/executor/projector decisions -> spec requirements: aligned.
|
||||
- spec scenarios -> tasks for dependency, policy, JDBC, projection, adapter and verification: aligned.
|
||||
- Interface impact: L2 internal Harness tool/adapter plus JSqlParser dependency and query-script behavior; no public protocol changes.
|
||||
- Preflight risk accepted: parser ambiguity, datasource isolation, driver cancellation behavior and sensitive result values all fail closed or remain Harness-only.
|
||||
|
||||
## Commit gate
|
||||
|
||||
- [x] proposal, design, specs and tasks exist.
|
||||
- [x] strict OpenSpec validation passes.
|
||||
- [x] all evidence-driven questions are resolved.
|
||||
- [x] no unresolved interface decision remains.
|
||||
- [x] `.committed` marker created for Apply.
|
||||
|
||||
## Apply result
|
||||
|
||||
- Added JSqlParser 4.6 and fail-closed `MysqlSqlValidator`.
|
||||
- Added immutable logical datasource/allowlist/limit/query-plan/raw-result models and independent `MysqlToolProperties` binding.
|
||||
- Added `JdbcMysqlReadOnlyExecutor` with read-only connection, PreparedStatement binding, query timeout, max rows, cell/result limits and Run cancellation callback.
|
||||
- Added `MysqlResultProjector` with sensitive-column redaction, row/cell/total UTF-8 bounds and `NO_EVIDENCE`.
|
||||
- Added `MysqlToolAdapter` through the existing ToolBoundary; invalid SQL is rejected before database execution.
|
||||
- Replaced `scripts/query_mysql.py` with environment-only, read-only transaction behavior and pre-connect write/metadata rejection.
|
||||
|
||||
## Apply conflicts and corrections
|
||||
|
||||
- `COUNT(*)` is represented by JSqlParser as an `AllColumns` parameter in this version; the visitor was corrected to permit only the explicit `COUNT(*)` exception.
|
||||
- JDBC metadata access cannot be used as a checked-exception stream method reference; the implementation uses an explicit column loop.
|
||||
- No OpenSpec/design conflict was found; both corrections were implementation details.
|
||||
|
||||
## Archive result
|
||||
|
||||
- Apply tasks complete and `.archive-ready` created.
|
||||
- OpenSpec archived at `openspec/changes/archive/2026-07-21-single-react-mysql-readonly-tool`.
|
||||
- Main capability specification added at `openspec/specs/mysql-readonly-tool/spec.md`.
|
||||
- Stage 4 may consume the internal adapter only after this stage is committed.
|
||||
@@ -0,0 +1,29 @@
|
||||
# Evidence: single-react-mysql-readonly-tool
|
||||
|
||||
## Static verification
|
||||
|
||||
- `git diff --check`: passed before archive.
|
||||
- Security scan confirms the query helper has no default external host/port/root user and no `commit()` write path.
|
||||
- New MySQL Harness code receives only injected logical DataSources and does not reference `spring.datasource` or the application persistence datasource.
|
||||
- OpenSpec strict validation passed for `single-react-mysql-readonly-tool`.
|
||||
|
||||
## Script/build verification
|
||||
|
||||
- `mvn -q -DskipTests compile`: passed.
|
||||
- Focused suite passed: `MysqlSqlValidatorTest`, `MysqlResultProjectorTest`, `JdbcMysqlReadOnlyExecutorTest`, `MysqlToolAdapterTest`, `MysqlToolContractTest`, `ToolBoundaryTest`, `CanonicalInvocationStoreTest`.
|
||||
- Python syntax compilation passed for `scripts/query_mysql.py`.
|
||||
- Missing connection environment variables exit before connection with code 2.
|
||||
- A write SQL invocation is rejected before connection with code 3.
|
||||
|
||||
## Security coverage
|
||||
|
||||
- Allowed: explicit allowlisted SELECT, parameter placeholders, qualified INNER JOIN and `COUNT(*)`.
|
||||
- Rejected: write, WITH, subquery, UNION, wildcard projection, unknown table/column, ambiguous column, dangerous function, inline literal, CASE, FOR UPDATE, multi-statement and placeholder mismatch.
|
||||
- JDBC controls verified: `setReadOnly(true)`, `PreparedStatement`, `setQueryTimeout`, `setMaxRows`, ordered parameter binding and cancellation-before-execution.
|
||||
- Projection controls verified: max rows, max cell chars, total UTF-8 bytes, sensitive-column redaction, valid bounded JSON and `NO_EVIDENCE`.
|
||||
|
||||
## Not verified in this stage
|
||||
|
||||
- No live production business datasource was provisioned or queried; ISS-014 explicitly assigns live E2E to a later issue/stage.
|
||||
- No public Diagnosis Agent/Chat integration was performed; stage 4 will consume the adapter internally.
|
||||
- JDBC driver timeout/cancel behavior against a real remote MySQL server remains an operational integration risk.
|
||||
Reference in New Issue
Block a user