secufusion-mcp 1.0.50 → 1.0.52
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 +33 -8
- package/README.md +15 -4
- package/index.js +1919 -0
- package/package.json +1 -1
|
@@ -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
|
@@ -466,21 +466,46 @@ STEP 3: do NOT repeat the rejected pattern — ever
|
|
|
466
466
|
## Phase 4 — PR Handoff
|
|
467
467
|
(TRIGGER: developer says "prepare PR", "run checks", or "ready to merge")
|
|
468
468
|
|
|
469
|
-
### MANDATORY sequence
|
|
469
|
+
### MANDATORY sequence — zero exceptions
|
|
470
470
|
|
|
471
471
|
```
|
|
472
|
-
STEP 1: call
|
|
473
|
-
—
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
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
|
|
479
500
|
```
|
|
480
501
|
|
|
481
502
|
### Hard enforcement
|
|
482
503
|
|
|
504
|
+
❌ Do NOT call `manage_task(complete)` before `run_pre_pr_checks_with_reviewer_agent` returns `APPROVED` or `DISCUSS`
|
|
483
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
|
+
|
|
484
509
|
|
|
485
510
|
## Phase 5 — Retrospective
|
|
486
511
|
(TRIGGER: after manage_task action=complete is called
|
package/README.md
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
| `manage_branch_state` | Legacy — Branch State | Backward-compatible branch-scoped JSON state tracker (for tasks before `manage_task`) |
|
|
23
23
|
| `log_rejected_pattern` | **Phase 3** — Course Correction | Records bad patterns to `.rejected-patterns.json` so they are never repeated |
|
|
24
24
|
| `generate_ado_comments` | **Phase 4** — PR Handoff | Generates distinct Layman and Technical Deep-Dive summaries for the Azure DevOps board |
|
|
25
|
+
| `run_pre_pr_checks_with_reviewer_agent` | **Phase 4** — PR Handoff | **NEW** — Unified 3-tier PR gate. Runs mechanical checks, AI file reviews, and context-aware task evaluation in a single pass. |
|
|
25
26
|
| `get_secufusion_rules` | **Setup** | Returns the `AGENTS.md` rules for AI clients that don't natively support MCP Resources |
|
|
26
27
|
| `classify_task` | **Phase 0.5** — Task Classification | **NEW** — Deep multi-pass analysis engine. Classifies any task as `BACKEND_ONLY`, `FRONTEND_ONLY`, `FULL_STACK`, or `EXTENSION_ONLY` based on root cause (where the fix lives), not surface symptoms. Must be the first tool called on any task. |
|
|
27
28
|
|
|
@@ -425,8 +426,9 @@ These rules are enforced automatically — the AI will never violate them:
|
|
|
425
426
|
│ Phase 3 │ log_rejected_pattern │
|
|
426
427
|
│ Correction │ → Record mistakes permanently to avoid repeat │
|
|
427
428
|
├──────────────┼──────────────────────────────────────────────────────────────┤
|
|
428
|
-
│ Phase 4 │
|
|
429
|
-
│ PR Handoff │
|
|
429
|
+
│ Phase 4 │ run_pre_pr_checks_with_reviewer_agent │
|
|
430
|
+
│ PR Handoff │ → manage_task (action=complete) → pr-summary.md generated │
|
|
431
|
+
│ │ → generate_ado_comments → Layman & Technical Deep-Dive (ADO) │
|
|
430
432
|
└──────────────┴──────────────────────────────────────────────────────────────┘
|
|
431
433
|
```
|
|
432
434
|
|
|
@@ -643,7 +645,8 @@ Phase 1: search_tasks (always) → get_task_history → manage_task initialize
|
|
|
643
645
|
↓
|
|
644
646
|
Phase 2: code + log_file_touched + log_decision + add_scenario (ALL mandatory)
|
|
645
647
|
↓
|
|
646
|
-
Phase 4:
|
|
648
|
+
Phase 4: run_pre_pr_checks_with_reviewer_agent → APPROVED / DISCUSS
|
|
649
|
+
→ manage_task complete → pr-summary.md generated
|
|
647
650
|
→ generate_ado_comments → Layman + Technical Deep-Dive for ADO board
|
|
648
651
|
```
|
|
649
652
|
|
|
@@ -686,6 +689,14 @@ As of version **1.0.24**, the MCP server introduces a fully automated **Retrospe
|
|
|
686
689
|
- **record_retrospective**: A new tool that saves retrospective insights, tracking plan accuracy, classification accuracy, and pre-PR check attempts.
|
|
687
690
|
- **Dynamic Learning (Pass 0)**: `classify_task` now includes a Pass 0 that injects learned signals from past retrospectives into the active classification logic.
|
|
688
691
|
|
|
692
|
+
### Rule 0 Enforcement & Frontend Fallbacks (v1.0.50+)
|
|
693
|
+
|
|
694
|
+
As of version **1.0.50**, the MCP server strictly enforces **Rule 0** and adds intelligent fallbacks:
|
|
695
|
+
- **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.
|
|
696
|
+
- **Auto-Syncing AGENTS.md**: The package now automatically syncs the workspace rules before publishing, guaranteeing AI agents always run the latest constraints.
|
|
697
|
+
- **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.
|
|
698
|
+
- **Explicit AC Recognition**: `classify_task` now overrides `VAGUE` completeness warnings if it detects explicit Acceptance Criteria in the task description.
|
|
699
|
+
|
|
689
700
|
---
|
|
690
701
|
|
|
691
702
|
## Talking to the AI — What You'll Ever Say
|
|
@@ -799,7 +810,7 @@ Proceeding to plan presentation. No developer confirmation needed.
|
|
|
799
810
|
| **Phase 1 (Planning)** | `"Call search_tasks if relevant"` | `search_tasks` is **unconditional** — STEP 1 always, even if "sure" there's no prior work |
|
|
800
811
|
| **Phase 2 (Execution)** | Bullet suggestions | MANDATORY code block for all 4 tool calls + `next_step` contract with explicit VIOLATION labels |
|
|
801
812
|
| **Phase 3 (Correction)** | `"Immediately call log_rejected_pattern"` | Explicit STEP 1/2/3 + ❌ list — log immediately, not end of session |
|
|
802
|
-
| **Phase 4 (PR Handoff)** | `"Call complete → run checks → fix if error"` | Explicit STEP 1-
|
|
813
|
+
| **Phase 4 (PR Handoff)** | `"Call complete → run checks → fix if error"` | Explicit STEP 1-3 **fix → recheck loop** until ZERO errors (Unified 3-tier check) |
|
|
803
814
|
| **Guardrails** | Mixed soft/hard language | All `should` → `MUST`, all `avoid` → `FORBIDDEN`, linter errors explicitly blocking |
|
|
804
815
|
| **Cross-Task Intelligence** | Prose bullets | MANDATORY STEP 1-4 sequence + ❌ list |
|
|
805
816
|
|