secufusion-mcp 1.0.49 → 1.0.51
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/.secufusion-project-spec.json +24 -17
- package/AGENTS.md +82 -31
- package/README.md +8 -0
- package/index.js +1901 -0
- package/package.json +2 -2
|
@@ -13,7 +13,19 @@
|
|
|
13
13
|
"commit_message_pattern": "No single enforced convention. Recurring mixture: (1) Azure Repos auto-generated 'Merged PR <number>: <title>' on PR completion (dominant pattern in all 3 sampled repos), (2) ticket-prefixed 'TASK-<number>: <desc>' or 'TASK-<number>-<desc>' (common in sfn-events-api), (3) conventional-commit style 'feat(<scope>): ...' / 'fix(<scope>): ...' (used consistently within recent 'ai-ops' feature work in sfn-web-ui, not elsewhere), (4) plain imperative descriptive messages with no prefix at all. Work items referenced via https://dev.azure.com/secufusion/SFCloud-MSSP/_workitems/edit/<id>."
|
|
14
14
|
},
|
|
15
15
|
"coding_patterns": {
|
|
16
|
-
"
|
|
16
|
+
"transactional_placement": "Method level only (never class level). @Transactional(readOnly = true) on read methods, plain @Transactional on write methods. Bulk-operation methods catch Exception per-item internally to accumulate a partial-failure result rather than aborting the whole batch.",
|
|
17
|
+
"exception_handling": "Custom unchecked exceptions (e.g. ResourceNotFoundException, ResourceConflictException) thrown from services, translated centrally by a @ControllerAdvice GlobalExceptionHandler into a flat JSON error body. Controllers additionally often wrap logic in try/catch to log with tenant/id context before rethrowing, which is somewhat redundant with the global handler.",
|
|
18
|
+
"tenant_id_passing": "Explicit String tenantId method parameter into services (not read from ThreadLocal inside the service itself); the controller resolves it once via TenantContextHolder.getActingTenantId() and passes it down.",
|
|
19
|
+
"dto_mapping": "Manual mapping via private convertToDTO()/convertToXxxDTO() helper methods in the service, building DTOs with Lombok @Builder. No MapStruct or ModelMapper used anywhere observed.",
|
|
20
|
+
"dto_suffix": "Inconsistent/mixed: DTO (uppercase) is most common for core domain response objects (e.g. IncidentDTO), Dto (mixed case) also appears (e.g. EventDto), Request is the standard suffix for inbound payloads (e.g. CreateIncidentRequest), Response appears in some newer modules (e.g. ExtensionApiKeyResponse).",
|
|
21
|
+
"lombok_style": "@Data + @Builder + @NoArgsConstructor + @AllArgsConstructor is the standard combination for request/response DTOs; @RequiredArgsConstructor for constructor-injected services; @Slf4j for logging on nearly every service/controller class.",
|
|
22
|
+
"response_wrapping": "Custom generic ResponseDto<T> { results, message, code } wrapper, always returned inside ResponseEntity<ResponseDto<T>>.",
|
|
23
|
+
"api_versioning": "None — base paths follow /api/<domain>/<resource> with no /v1/ or similar version segment anywhere across the platform.",
|
|
24
|
+
"test_naming_convention": "Not fully uniform. Predominantly camelCase descriptive sentence-style method names (e.g. refreshReplacesStaleSecretOnExistingRowAndPrimesCache); some newer test classes instead use snake_case sentence names with @Nested + @DisplayName groupings (e.g. blacklisted_extension_is_blocked_regardless_of_risk). Class-name suffixes are meaningful and consistent: *Test (unit), *IntegrationTest (Testcontainers-backed), *BaselineTest / *RegressionTest / *GuardrailTest (behavior-pinning regression tests), *ContractTest (Kafka payload contracts), *MigrationTest (Flyway migration verification).",
|
|
25
|
+
"assertion_library": "AssertJ (assertThat(...)) is the house standard; plain JUnit assertEquals/assertTrue not used in the sampled files.",
|
|
26
|
+
"query_style": "Mixed within the same repository interfaces: derived query methods (Spring Data naming, incl. nested-property navigation like findByXAndTenant_TenantID), plus @Query using both JPQL and native SQL (native used especially for optional-filter idioms and GROUP BY/aggregate stats queries).",
|
|
27
|
+
"tenant_filter_pattern": "No single universal mechanism. Combination of: (1) explicit tenantId predicate inside @Query/derived repository methods for most tenant-owned entities, (2) a centralized fail-closed HandlerInterceptor (TenantAccessInterceptor, most fully built out in sfn-iam-api and sfn-tenants-api) that validates any tenantId path-variable/query-param against the JWT-resolved acting tenant before the controller runs, (3) explicit service/controller-level TenantAccessGuard.requireCallerCanAccess(...) checks for endpoints addressed by a non-tenant id (e.g. a bare userId), and (4) a small number of repositories/entities are deliberately global/unscoped reference data (countries, package catalogs, scopes, etc.) — see manual_review_flags for entities where this determination could not be fully verified from code alone.",
|
|
28
|
+
"timestamp_handling": "Architecture Rule: The backend ONLY produces UTC timestamp strings. All time formatting and local timezone conversion MUST be handled by the frontend. The backend never returns pre-formatted display strings like timeDisplay or dateDisplay."
|
|
17
29
|
},
|
|
18
30
|
"microservices": {
|
|
19
31
|
"sfn-auth-api": {
|
|
@@ -1012,21 +1024,6 @@
|
|
|
1012
1024
|
"mismatch_validation": true
|
|
1013
1025
|
}
|
|
1014
1026
|
},
|
|
1015
|
-
"coding_patterns": {
|
|
1016
|
-
"transactional_placement": "Method level only (never class level). @Transactional(readOnly = true) on read methods, plain @Transactional on write methods. Bulk-operation methods catch Exception per-item internally to accumulate a partial-failure result rather than aborting the whole batch.",
|
|
1017
|
-
"exception_handling": "Custom unchecked exceptions (e.g. ResourceNotFoundException, ResourceConflictException) thrown from services, translated centrally by a @ControllerAdvice GlobalExceptionHandler into a flat JSON error body. Controllers additionally often wrap logic in try/catch to log with tenant/id context before rethrowing, which is somewhat redundant with the global handler.",
|
|
1018
|
-
"tenant_id_passing": "Explicit String tenantId method parameter into services (not read from ThreadLocal inside the service itself); the controller resolves it once via TenantContextHolder.getActingTenantId() and passes it down.",
|
|
1019
|
-
"dto_mapping": "Manual mapping via private convertToDTO()/convertToXxxDTO() helper methods in the service, building DTOs with Lombok @Builder. No MapStruct or ModelMapper used anywhere observed.",
|
|
1020
|
-
"dto_suffix": "Inconsistent/mixed: DTO (uppercase) is most common for core domain response objects (e.g. IncidentDTO), Dto (mixed case) also appears (e.g. EventDto), Request is the standard suffix for inbound payloads (e.g. CreateIncidentRequest), Response appears in some newer modules (e.g. ExtensionApiKeyResponse).",
|
|
1021
|
-
"lombok_style": "@Data + @Builder + @NoArgsConstructor + @AllArgsConstructor is the standard combination for request/response DTOs; @RequiredArgsConstructor for constructor-injected services; @Slf4j for logging on nearly every service/controller class.",
|
|
1022
|
-
"response_wrapping": "Custom generic ResponseDto<T> { results, message, code } wrapper, always returned inside ResponseEntity<ResponseDto<T>>.",
|
|
1023
|
-
"api_versioning": "None — base paths follow /api/<domain>/<resource> with no /v1/ or similar version segment anywhere across the platform.",
|
|
1024
|
-
"test_naming_convention": "Not fully uniform. Predominantly camelCase descriptive sentence-style method names (e.g. refreshReplacesStaleSecretOnExistingRowAndPrimesCache); some newer test classes instead use snake_case sentence names with @Nested + @DisplayName groupings (e.g. blacklisted_extension_is_blocked_regardless_of_risk). Class-name suffixes are meaningful and consistent: *Test (unit), *IntegrationTest (Testcontainers-backed), *BaselineTest / *RegressionTest / *GuardrailTest (behavior-pinning regression tests), *ContractTest (Kafka payload contracts), *MigrationTest (Flyway migration verification).",
|
|
1025
|
-
"assertion_library": "AssertJ (assertThat(...)) is the house standard; plain JUnit assertEquals/assertTrue not used in the sampled files.",
|
|
1026
|
-
"query_style": "Mixed within the same repository interfaces: derived query methods (Spring Data naming, incl. nested-property navigation like findByXAndTenant_TenantID), plus @Query using both JPQL and native SQL (native used especially for optional-filter idioms and GROUP BY/aggregate stats queries).",
|
|
1027
|
-
"tenant_filter_pattern": "No single universal mechanism. Combination of: (1) explicit tenantId predicate inside @Query/derived repository methods for most tenant-owned entities, (2) a centralized fail-closed HandlerInterceptor (TenantAccessInterceptor, most fully built out in sfn-iam-api and sfn-tenants-api) that validates any tenantId path-variable/query-param against the JWT-resolved acting tenant before the controller runs, (3) explicit service/controller-level TenantAccessGuard.requireCallerCanAccess(...) checks for endpoints addressed by a non-tenant id (e.g. a bare userId), and (4) a small number of repositories/entities are deliberately global/unscoped reference data (countries, package catalogs, scopes, etc.) — see manual_review_flags for entities where this determination could not be fully verified from code alone.",
|
|
1028
|
-
"timestamp_handling": "Architecture Rule: The backend ONLY produces UTC timestamp strings. All time formatting and local timezone conversion MUST be handled by the frontend. The backend never returns pre-formatted display strings like timeDisplay or dateDisplay."
|
|
1029
|
-
},
|
|
1030
1027
|
"golden_rules": {
|
|
1031
1028
|
"tenant_isolation": "Multi-layered, not enforced by a single mechanism: JWT issuer resolves caller tenant via per-tenant DB-stored Keycloak config (DbJwtAuthenticationManagerResolver, duplicated across 5 services) -> TenantContextHolder holds the acting tenant for the request -> optional MSSP 'acting tenant' impersonation override via X-Acting-Tenant header or /api/tenants/{tenantId}/... path prefix, gated by ParentChainAuthorizer.isCallerAncestorOrSelf + PrivacyLevelEnforcer.canImpersonate -> TenantAccessInterceptor/TenantAccessGuard perform a fail-closed check of any tenantId path-var/query-param against the acting tenant (most complete in sfn-iam-api and sfn-tenants-api) -> individual repository query methods additionally filter by tenantId for tenant-owned entities. No .rejected-patterns.json file exists anywhere in the workspace to source a canonical, explicitly-authored rule set from — this description is reconstructed from code, not an authored policy document.",
|
|
1032
1029
|
"rejected_patterns": [],
|
|
@@ -1035,7 +1032,17 @@
|
|
|
1035
1032
|
"Platform-wide/cross-tenant operations bypass the per-domain authority scheme and instead use bespoke role/type checks: requirePlatformAdmin() and TenantTypeEnum.PLATFORM_ADMIN (sfn-iam-api), requireMasterMsspAdmin()/requireTenantBundleAdmin() checking for role strings 'MASTER MSSP ADMIN'/'MSSP ADMIN' (sfn-policy-api's rules-engine bundle publishing).",
|
|
1036
1033
|
"Service-account/machine-to-machine requests (browser extension bootstrap, rules-engine publisher, public device/extension enrollment endpoints) are authenticated by JWT azp + issuer matching rather than a user authority, and are explicitly permitAll'd in each service's SecurityConfig under /api/*/public/** or /.well-known/** paths."
|
|
1037
1034
|
],
|
|
1038
|
-
"explicitly_banned": []
|
|
1035
|
+
"explicitly_banned": [],
|
|
1036
|
+
"coding_style": {
|
|
1037
|
+
"applies_to": [
|
|
1038
|
+
"Java",
|
|
1039
|
+
"TypeScript",
|
|
1040
|
+
"all languages"
|
|
1041
|
+
],
|
|
1042
|
+
"banned_pattern": "if (x == null) return; OR if (!valid) return value;",
|
|
1043
|
+
"conditionals": "Always nested positive if blocks. Never early returns or guard clauses. Single return point at method end.",
|
|
1044
|
+
"correct_pattern": "if (x != null) { if (valid) { result = work(); } } return result;"
|
|
1045
|
+
}
|
|
1039
1046
|
},
|
|
1040
1047
|
"current_state": {
|
|
1041
1048
|
"active_branch": "Multi-repo — no single active branch. sfn-events-api and sfn-web-ui were checked out on 'develop' at analysis time; snf-browser-extn was checked out on 'main'.",
|
package/AGENTS.md
CHANGED
|
@@ -9,44 +9,70 @@ You are an elite Senior Developer and Architect working on the SecuFusion worksp
|
|
|
9
9
|
|
|
10
10
|
**DYNAMIC ENFORCEMENT**: You must dynamically adhere to these rules at all times. Whether you are starting a fresh task, resuming an interrupted session, or answering a mid-task prompt, you must strictly respect this sequence and never skip ahead.
|
|
11
11
|
|
|
12
|
-
1. **Rule
|
|
13
|
-
2. **Rule
|
|
14
|
-
3. **Rule
|
|
15
|
-
4. **Rule
|
|
16
|
-
5. **Rule
|
|
12
|
+
1. **Rule 0 (Pre-requisite to all rules) — Load Project DNA First**: Before ANY other action, call `manage_project_spec(action: "read")` then `manage_project_spec(action: "get_golden_rules")`. This is Phase 00. Without the project DNA loaded, you are not allowed to reason, classify, plan, or code. Period.
|
|
13
|
+
2. **Rule 1 - ReAct (Reason, Observe, Act) First**: After DNA is loaded, you MUST deeply reason about the problem statement. Apply the ReAct framework: analyze the problem, observe context, and formulate a high-level solution hypothesis.
|
|
14
|
+
3. **Rule 2 - Classify Second**: Only after you have reasoned through the problem statement, you MUST call the `classify_task` tool. This will formally categorize the task and lock in architectural boundaries.
|
|
15
|
+
4. **Rule 3 - STRICT YIELD (Stop and Wait)**: Immediately after classifying the task, you MUST YIELD YOUR TURN. **DO NOT CHAIN TOOL CALLS.** Output the classification, ask the user for the "green signal," and STOP.
|
|
16
|
+
5. **Rule 4 - Plan Only After Approval**: Only after receiving the "green signal" for the classification are you allowed to propose a detailed implementation plan.
|
|
17
|
+
6. **Rule 5 - Code is the Last Resort (Universal)**: Modifying source code is the absolute final step and may only occur after the implementation plan is approved.
|
|
17
18
|
|
|
18
19
|
---
|
|
19
20
|
|
|
20
|
-
## Phase 00 — Project
|
|
21
|
-
(TRIGGER: **every session start
|
|
21
|
+
## Phase 00 — Load Project DNA (The Absolute First Step)
|
|
22
|
+
(TRIGGER: **every session start, no exceptions, no shortcuts, regardless of task type**)
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
> 🧬 **The project DNA MUST be loaded before you do ANYTHING ELSE.**
|
|
25
|
+
> No task reasoning. No problem analysis. No responses. No tool calls of any other kind.
|
|
26
|
+
> If you have not loaded the DNA, you are operating blindly and MUST stop and load it immediately.
|
|
27
|
+
|
|
28
|
+
### MANDATORY sequence — zero exceptions, zero shortcuts
|
|
24
29
|
|
|
25
30
|
```
|
|
26
|
-
STEP 1
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
STEP 1 — ALWAYS, unconditionally:
|
|
32
|
+
→ call manage_project_spec(action: "read")
|
|
33
|
+
This loads ALL microservices, ports, repos, Kafka topics, auth flow,
|
|
34
|
+
table ownership, Keycloak config, and inter-service calls into context.
|
|
35
|
+
|
|
36
|
+
STEP 2 — ALWAYS, unconditionally:
|
|
37
|
+
→ call manage_project_spec(action: "get_golden_rules")
|
|
38
|
+
This loads all non-negotiable architectural guardrails.
|
|
39
|
+
|
|
40
|
+
STEP 3 — if you are working on a specific service:
|
|
41
|
+
→ call manage_project_spec(action: "get_service", service_name: <that service>)
|
|
30
42
|
```
|
|
31
43
|
|
|
32
|
-
|
|
33
|
-
|
|
44
|
+
After these calls complete, you now know:
|
|
45
|
+
- All service ports, repos, domains
|
|
46
|
+
- Table ownership per service
|
|
47
|
+
- All inter-service REST calls
|
|
48
|
+
- Kafka topics (produces/consumes per service)
|
|
49
|
+
- Keycloak config and auth flow
|
|
50
|
+
- Coding patterns and golden rules
|
|
51
|
+
|
|
52
|
+
You are NOW allowed to reason about the task. Not before.
|
|
53
|
+
|
|
54
|
+
### Why this is non-negotiable
|
|
34
55
|
|
|
35
|
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
56
|
+
`classify_task` does a background scan of the project spec JSON file, but the **AI agent itself** must independently load the spec into its own active context. The background scan is not a substitute. Without this step, the agent:
|
|
57
|
+
- Cannot accurately reason about service boundaries
|
|
58
|
+
- Cannot validate task scope against architecture
|
|
59
|
+
- Cannot enforce golden rules during classification
|
|
60
|
+
- Will hallucinate service details from memory
|
|
39
61
|
|
|
40
|
-
|
|
62
|
+
There are NO circumstances under which Phase 00 can be skipped, abbreviated, or substituted.
|
|
41
63
|
|
|
64
|
+
### Hard enforcement — what you are FORBIDDEN from doing before Phase 00 completes
|
|
65
|
+
|
|
66
|
+
❌ Respond to the user's message
|
|
67
|
+
❌ Reason about the task or problem statement
|
|
68
|
+
❌ Call `classify_task`
|
|
42
69
|
❌ Ask the developer which service owns what
|
|
43
70
|
❌ Ask what port something runs on
|
|
44
|
-
❌
|
|
45
|
-
❌ Assume any service details from memory
|
|
71
|
+
❌ Assume ANY service details from memory
|
|
46
72
|
❌ Write any code
|
|
47
|
-
❌ Proceed to any other phase
|
|
73
|
+
❌ Proceed to Phase 0.5 or any other phase
|
|
48
74
|
|
|
49
|
-
The ONLY tool calls permitted
|
|
75
|
+
The ONLY tool calls permitted before Phase 00 completes are the `manage_project_spec` calls listed above.
|
|
50
76
|
|
|
51
77
|
---
|
|
52
78
|
|
|
@@ -440,21 +466,46 @@ STEP 3: do NOT repeat the rejected pattern — ever
|
|
|
440
466
|
## Phase 4 — PR Handoff
|
|
441
467
|
(TRIGGER: developer says "prepare PR", "run checks", or "ready to merge")
|
|
442
468
|
|
|
443
|
-
### MANDATORY sequence
|
|
469
|
+
### MANDATORY sequence — zero exceptions
|
|
444
470
|
|
|
445
471
|
```
|
|
446
|
-
STEP 1: call
|
|
447
|
-
—
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
472
|
+
STEP 1: call run_pre_pr_checks_with_reviewer_agent(work_item_id: <id>)
|
|
473
|
+
— Tier 1: 5 mechanical checks
|
|
474
|
+
P1 TENANT_ISOLATION — every Repository query scoped to tenantId
|
|
475
|
+
P2 N_PLUS_ONE — no repo calls inside loops
|
|
476
|
+
P3 MISSING_INDEX — new query columns have migration index
|
|
477
|
+
P4 KAFKA_SYNC — no sync work inside @KafkaListener
|
|
478
|
+
P5 EARLY_RETURN — no early returns (single-exit rule)
|
|
479
|
+
— Tier 2: AI File Reviewer (only after P1–P5 pass)
|
|
480
|
+
Checks: hardcoded URLs, missing @Transactional(readOnly),
|
|
481
|
+
missing @PreAuthorize, debug statements, exception swallowing,
|
|
482
|
+
TS `any` overuse, missing Flyway for @Entity, cross-service timeouts
|
|
483
|
+
— Tier 3: Context Reviewer (only after Tier 2 passes)
|
|
484
|
+
Reads: spec.json, progress.json, decisions.json, scenarios.json,
|
|
485
|
+
files-touched.json, project-spec golden_rules, rejected patterns
|
|
486
|
+
Cross-references: AC coverage, decision drift, scope creep,
|
|
487
|
+
rejected patterns in file content, test coverage gaps, golden rules
|
|
488
|
+
— Verdict: APPROVED | CHANGES_REQUESTED | DISCUSS
|
|
489
|
+
→ If CHANGES_REQUESTED: fix all ❌ findings, then re-run this step
|
|
490
|
+
→ If APPROVED or DISCUSS: proceed to Step 2
|
|
491
|
+
|
|
492
|
+
STEP 2: call manage_task(action: "complete", work_item_id: <id>)
|
|
493
|
+
— Only permitted after APPROVED or DISCUSS verdict
|
|
494
|
+
— Marks status complete, auto-generates pr-summary.md
|
|
495
|
+
|
|
496
|
+
STEP 3: call generate_ado_comments(work_item_id, layman_summary, technical_deep_dive)
|
|
497
|
+
— Generates two ADO board comments:
|
|
498
|
+
1. Layman Summary: non-technical explanation of business value
|
|
499
|
+
2. Technical Deep-Dive: architectural changes and implementation details
|
|
453
500
|
```
|
|
454
501
|
|
|
455
502
|
### Hard enforcement
|
|
456
503
|
|
|
504
|
+
❌ Do NOT call `manage_task(complete)` before `run_pre_pr_checks_with_reviewer_agent` returns `APPROVED` or `DISCUSS`
|
|
457
505
|
❌ Do NOT raise a PR while `pending_acs` is non-empty
|
|
506
|
+
❌ Do NOT raise a PR if the verdict is `CHANGES_REQUESTED`
|
|
507
|
+
❌ Do NOT skip the tool and declare the code "obviously clean" — the three tiers catch different classes of issues
|
|
508
|
+
|
|
458
509
|
|
|
459
510
|
## Phase 5 — Retrospective
|
|
460
511
|
(TRIGGER: after manage_task action=complete is called
|
package/README.md
CHANGED
|
@@ -686,6 +686,14 @@ As of version **1.0.24**, the MCP server introduces a fully automated **Retrospe
|
|
|
686
686
|
- **record_retrospective**: A new tool that saves retrospective insights, tracking plan accuracy, classification accuracy, and pre-PR check attempts.
|
|
687
687
|
- **Dynamic Learning (Pass 0)**: `classify_task` now includes a Pass 0 that injects learned signals from past retrospectives into the active classification logic.
|
|
688
688
|
|
|
689
|
+
### Rule 0 Enforcement & Frontend Fallbacks (v1.0.50+)
|
|
690
|
+
|
|
691
|
+
As of version **1.0.50**, the MCP server strictly enforces **Rule 0** and adds intelligent fallbacks:
|
|
692
|
+
- **Rule 0 (DNA Load First)**: Agents are now strictly forbidden from reasoning, classifying, or planning until they have called `manage_project_spec` to load the project DNA.
|
|
693
|
+
- **Auto-Syncing AGENTS.md**: The package now automatically syncs the workspace rules before publishing, guaranteeing AI agents always run the latest constraints.
|
|
694
|
+
- **Frontend Service Resolution**: `get_service` now intelligently resolves frontend and extension repositories (like `sfn-web-ui`) even when they aren't explicitly keyed as backend microservices.
|
|
695
|
+
- **Explicit AC Recognition**: `classify_task` now overrides `VAGUE` completeness warnings if it detects explicit Acceptance Criteria in the task description.
|
|
696
|
+
|
|
689
697
|
---
|
|
690
698
|
|
|
691
699
|
## Talking to the AI — What You'll Ever Say
|