@hoanghainh/komagu 1.7.0 → 2.0.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.
Files changed (84) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/assess/lsa/CHANGELOG.md +6 -0
  3. package/assess/lsa/VERSION +1 -1
  4. package/assess/lsa/adapters/build_adapters.py +16 -8
  5. package/assess/lsa/adapters/codex/README.md +1 -1
  6. package/assess/lsa/adapters/generic/README.md +1 -1
  7. package/assess/lsa/knowledge/severity-and-cwe.md +1 -1
  8. package/assess/lsa/scripts/baseline.py +5 -2
  9. package/assess/lsa/scripts/findings_to_sarif.py +24 -1
  10. package/assess/lsa/tests/test_adapters.py +21 -2
  11. package/assess/lsa/tests/test_baseline.py +8 -0
  12. package/assess/lsa/tests/test_contract_groundwork.py +7 -7
  13. package/operate/cli/__init__.py +1 -1
  14. package/operate/cli/commands/scan.py +2 -7
  15. package/operate/cli/commands/test.py +1 -1
  16. package/operate/cli/env.py +4 -20
  17. package/operate/cross_user_tester/persona_matrix.py +5 -1
  18. package/operate/devsecops/pipeline.py +5 -5
  19. package/operate/exploit/generator.py +5 -1
  20. package/operate/lsa_sarif/lsa_to_sarif.py +24 -2
  21. package/operate/lsa_sarif/sarif_findings.py +96 -0
  22. package/operate/remediator/runner.py +1 -5
  23. package/operate/remediator/strategies.py +1 -1
  24. package/operate/tests/test_cli_baseline.py +1 -9
  25. package/operate/tests/test_cli_env.py +8 -29
  26. package/operate/tests/test_cross_user_pipeline.py +2 -2
  27. package/operate/tests/test_exploit_and_virtual_patch.py +3 -3
  28. package/operate/tests/test_npm_package.py +2 -16
  29. package/operate/tests/test_sarif_from_scan.py +156 -0
  30. package/package.json +2 -4
  31. package/remediate/authz/README.md +1 -1
  32. package/remediate/authz/dotnet/src/Komagu.Security.Authorization/DefaultKomaguAuthorizationService.cs +1 -1
  33. package/remediate/authz/dotnet/src/Komagu.Security.Authorization/SecurityAuditEvent.cs +2 -2
  34. package/remediate/authz/golang/authz.go +1 -1
  35. package/remediate/authz/nodejs/src/service.js +1 -1
  36. package/remediate/authz/nodejs/tests/test-authz.js +1 -1
  37. package/remediate/authz/patcher.py +3 -4
  38. package/remediate/authz/python/komagu_authz/models.py +2 -2
  39. package/remediate/authz/python/tests/test_fastapi_adapter.py +1 -1
  40. package/remediate/authz/python/tests/test_fastapi_d5_crosstest.py +1 -1
  41. package/remediate/authz/python/tests/test_python_authz.py +3 -3
  42. package/remediate/authz/spring/src/main/kotlin/io/komagu/security/authorization/DefaultKomaguSecurityManager.kt +1 -1
  43. package/remediate/authz/spring/src/main/kotlin/io/komagu/security/authorization/SecurityAuditEvent.kt +1 -2
  44. package/remediate/authz/tests/test_bola_patcher.py +1 -1
  45. package/remediate/edge/coraza/rules/coraza-crs-custom.conf +3 -4
  46. package/remediate/edge/coraza/virtual_patcher.py +4 -6
  47. package/remediate/edge/docker-compose.yml +1 -1
  48. package/remediate/ekyc/server/jpki_verifier.py +2 -8
  49. package/remediate/ekyc/server/tokenization.py +2 -8
  50. package/remediate/identity/README.md +5 -5
  51. package/remediate/identity/dotnet/src/Komagu.Security.Identity/KomaguOidcOptions.cs +2 -2
  52. package/remediate/identity/dotnet/tests/Komagu.Security.Identity.Tests/TestTokenGenerator.cs +1 -1
  53. package/remediate/identity/dotnet/tests/Komagu.Security.Identity.Tests/TokenValidationTests.cs +1 -1
  54. package/remediate/identity/python/komagu_identity/oidc_validator.py +2 -8
  55. package/remediate/identity/python/tests/test_oidc_validator.py +1 -1
  56. package/remediate/identity/spring/src/main/kotlin/io/komagu/security/identity/KomaguOidcProperties.kt +2 -2
  57. package/remediate/identity/spring/src/test/kotlin/io/komagu/security/identity/KomaguIdentityAutoConfigurationTest.kt +2 -2
  58. package/remediate/identity/spring/src/test/kotlin/io/komagu/security/identity/TestJwtFactory.kt +1 -1
  59. package/remediate/identity/spring/src/test/kotlin/io/komagu/security/identity/TokenValidationIntegrationTest.kt +1 -1
  60. package/remediate/identity/test-env/realm-komagu.json +1 -1
  61. package/remediate/legacy_shims/coldfusion/KomaguSecurityShim.cfc +5 -5
  62. package/remediate/query/README.md +1 -1
  63. package/remediate/query/dotnet/src/Komagu.Security.Query.Analyzers/DiagnosticIds.cs +1 -1
  64. package/remediate/query/dotnet/src/Komagu.Security.Query.Analyzers/Komagu.Security.Query.Analyzers.csproj +1 -1
  65. package/remediate/query/spring/src/main/kotlin/io/komagu/security/query/detekt/KomaguRuleSetProvider.kt +1 -1
  66. package/remediate/resilience/dr/dr_manager.py +2 -8
  67. package/remediate/resilience/dr/runbook.md +2 -2
  68. package/remediate/resilience/terraform/variables.tf +1 -1
  69. package/remediate/tenancy/audit/audit_trail.py +2 -8
  70. package/remediate/tenancy/crypto/byok_manager.py +2 -8
  71. package/remediate/tenancy/middleware/tenant_context.py +2 -8
  72. package/remediate/tenancy/sql/rls_isolation.sql +11 -11
  73. package/remediate/tenancy/sql/schema_per_tenant.sql +7 -7
  74. package/remediate/tenancy/test_sql_postgres.py +1 -1
  75. package/remediate/tenancy/tests/test_tenancy.py +4 -4
  76. package/bin/komainu +0 -16
  77. package/bin/komainu-legacy.js +0 -16
  78. package/remediate/ekyc/tests/test_legacy_env.py +0 -33
  79. package/remediate/identity/python/tests/test_legacy_env.py +0 -33
  80. package/remediate/identity/spring/src/main/kotlin/io/komagu/security/identity/LegacyKomainuPropertiesPostProcessor.kt +0 -60
  81. package/remediate/identity/spring/src/main/resources/META-INF/spring.factories +0 -2
  82. package/remediate/identity/spring/src/test/kotlin/io/komagu/security/identity/LegacyKomainuPropertiesPostProcessorTest.kt +0 -86
  83. package/remediate/resilience/tests/test_legacy_env.py +0 -33
  84. package/remediate/tenancy/tests/test_legacy_env.py +0 -49
@@ -22,18 +22,12 @@ import re
22
22
  import secrets
23
23
  import sys
24
24
  import time
25
- import warnings
26
25
  from typing import Any, Dict, List, Optional, Set, Tuple
27
26
 
28
27
 
29
28
  def _env(name: str, default: Optional[str] = None) -> Optional[str]:
30
- """Read KOMAGU_<name>, falling back to the deprecated KOMAINU_<name> (#290)."""
31
- value = os.environ.get("KOMAGU_" + name)
32
- if value is None:
33
- value = os.environ.get("KOMAINU_" + name)
34
- if value is not None:
35
- warnings.warn(f"KOMAINU_{name} is deprecated, set KOMAGU_{name} instead", DeprecationWarning, stacklevel=2)
36
- return default if value is None else value
29
+ """Read KOMAGU_<name>."""
30
+ return os.environ.get("KOMAGU_" + name, default)
37
31
 
38
32
 
39
33
  # Allowed fields in API requests under Zero-PII contract
@@ -15,7 +15,7 @@ Every incoming request bearing an access token is validated against 5 mandatory
15
15
  | **Missing Token** | No `Authorization: Bearer <token>` header supplied. | **HTTP 401 Unauthorized** |
16
16
  | **Token Expiry** | Current timestamp > `exp` claim (`ClockSkew` enforced to 0s or strict delta). | **HTTP 401 Unauthorized** |
17
17
  | **Issuer Validation** | Token `iss` claim does not match configured trusted IdP authority. | **HTTP 401 Unauthorized** |
18
- | **Audience Validation** | Token `aud` claim does not include the target resource server ID (`komainu-api`). | **HTTP 401 Unauthorized** |
18
+ | **Audience Validation** | Token `aud` claim does not include the target resource server ID (`komagu-api`). | **HTTP 401 Unauthorized** |
19
19
  | **Cryptographic Signature** | Token signed by untrusted key or payload tampered with. | **HTTP 401 Unauthorized** |
20
20
 
21
21
  ---
@@ -36,7 +36,7 @@ Keycloak starts at `http://localhost:8080` with the `komagu` realm pre-loaded:
36
36
  - **Realm Discovery URL:** `http://localhost:8080/realms/komagu/.well-known/openid-configuration`
37
37
  - **Clients:**
38
38
  - `komagu-portal`: Public SPA client (Standard Flow + PKCE enforced)
39
- - `komainu-api`: Resource server bearer-only client (`aud`: `komainu-api`)
39
+ - `komagu-api`: Resource server bearer-only client (`aud`: `komagu-api`)
40
40
  - **Test Personas:**
41
41
  - `alice` (Password: `password123`, Tenant: `tenant-alpha`, Role: `Member`)
42
42
  - `bob` (Password: `password123`, Tenant: `tenant-alpha`, Role: `Member`)
@@ -58,7 +58,7 @@ var builder = WebApplication.CreateBuilder(args);
58
58
  builder.Services.AddKomaguJwtAuthentication(options =>
59
59
  {
60
60
  options.Issuer = builder.Configuration["Authentication:Issuer"] ?? "https://auth.komagu.test/realms/komagu";
61
- options.Audience = "komainu-api";
61
+ options.Audience = "komagu-api";
62
62
  options.RequireHttpsMetadata = builder.Environment.IsProduction();
63
63
  options.ClockSkew = TimeSpan.Zero;
64
64
  });
@@ -82,13 +82,13 @@ komagu:
82
82
  security:
83
83
  oidc:
84
84
  issuer: "https://auth.komagu.test/realms/komagu"
85
- audience: "komainu-api"
85
+ audience: "komagu-api"
86
86
  jwk-set-uri: "https://auth.komagu.test/realms/komagu/protocol/openid-connect/certs"
87
87
  clock-skew-seconds: 0
88
88
  ```
89
89
 
90
90
  The auto-configuration registers:
91
- 1. `KomaguAudienceValidator`: Enforces `aud == komainu-api`.
91
+ 1. `KomaguAudienceValidator`: Enforces `aud == komagu-api`.
92
92
  2. `KomaguJwtAuthenticationConverter`: Maps `sub` to principal and `tenant_id` claim to authentication details.
93
93
  3. Stateless `SecurityFilterChain` permitting public endpoints and enforcing authentication on all other APIs.
94
94
 
@@ -13,10 +13,10 @@ public sealed class KomaguOidcOptions
13
13
  public string Issuer { get; set; } = string.Empty;
14
14
 
15
15
  /// <summary>
16
- /// Expected resource server audience identifier (e.g. "komainu-api").
16
+ /// Expected resource server audience identifier (e.g. "komagu-api").
17
17
  /// The pre-rename default is kept so issued tokens stay valid (#290).
18
18
  /// </summary>
19
- public string Audience { get; set; } = "komainu-api";
19
+ public string Audience { get; set; } = "komagu-api";
20
20
 
21
21
  /// <summary>
22
22
  /// OIDC well-known configuration endpoint URI.
@@ -18,7 +18,7 @@ public sealed class TestTokenGenerator : IDisposable
18
18
 
19
19
  public string GenerateToken(
20
20
  string issuer = "https://auth.komagu.test/realms/komagu",
21
- string audience = "komainu-api",
21
+ string audience = "komagu-api",
22
22
  string userId = "user-alice",
23
23
  string tenantId = "tenant-alpha",
24
24
  DateTime? expires = null,
@@ -14,7 +14,7 @@ using Xunit;
14
14
  public class TokenValidationTests : IDisposable
15
15
  {
16
16
  private const string ExpectedIssuer = "https://auth.komagu.test/realms/komagu";
17
- private const string ExpectedAudience = "komainu-api";
17
+ private const string ExpectedAudience = "komagu-api";
18
18
 
19
19
  private readonly TestTokenGenerator _tokenGenerator;
20
20
  private readonly TestServer _server;
@@ -11,7 +11,6 @@ from __future__ import annotations
11
11
  import math
12
12
  import os
13
13
  import sys
14
- import warnings
15
14
  from typing import Any, Dict, List, Optional, Union
16
15
 
17
16
  import jwt
@@ -33,13 +32,8 @@ from .models import UserPrincipal
33
32
 
34
33
 
35
34
  def _env(name: str, default: Optional[str] = None) -> Optional[str]:
36
- """Read KOMAGU_<name>, falling back to the deprecated KOMAINU_<name> (#290)."""
37
- value = os.environ.get("KOMAGU_" + name)
38
- if value is None:
39
- value = os.environ.get("KOMAINU_" + name)
40
- if value is not None:
41
- warnings.warn(f"KOMAINU_{name} is deprecated, set KOMAGU_{name} instead", DeprecationWarning, stacklevel=2)
42
- return default if value is None else value
35
+ """Read KOMAGU_<name>."""
36
+ return os.environ.get("KOMAGU_" + name, default)
43
37
 
44
38
 
45
39
  # Standard test/dev personas matching Komagu cross-user test fixtures
@@ -44,7 +44,7 @@ class TestOidcTokenValidator(unittest.TestCase):
44
44
  cls.attacker_private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
45
45
 
46
46
  cls.issuer = "https://identity.komagu.test"
47
- cls.audience = "komainu-api"
47
+ cls.audience = "komagu-api"
48
48
 
49
49
  def _create_token(
50
50
  self,
@@ -13,10 +13,10 @@ data class KomaguOidcProperties(
13
13
  var issuer: String = "",
14
14
 
15
15
  /**
16
- * Expected resource server audience (default: "komainu-api"). Must not be blank.
16
+ * Expected resource server audience (default: "komagu-api"). Must not be blank.
17
17
  * The pre-rename default is kept so issued tokens stay valid (#290).
18
18
  */
19
- var audience: String = "komainu-api",
19
+ var audience: String = "komagu-api",
20
20
 
21
21
  /**
22
22
  * JSON Web Key Set (JWKS) endpoint URI. Must use HTTPS unless allowInsecureHttpJwks is true.
@@ -101,7 +101,7 @@ class KomaguIdentityAutoConfigurationTest {
101
101
 
102
102
  val port = server.address.port
103
103
  val issuer = "https://auth.komagu.test/realms/komagu"
104
- val audience = "komainu-api"
104
+ val audience = "komagu-api"
105
105
 
106
106
  try {
107
107
  contextRunner
@@ -255,7 +255,7 @@ class KomaguIdentityAutoConfigurationTest {
255
255
  }
256
256
  server.start()
257
257
 
258
- val audience = "komainu-api"
258
+ val audience = "komagu-api"
259
259
 
260
260
  try {
261
261
  // Configure ONLY spring.security.oauth2.resourceserver.jwt.issuer-uri
@@ -26,7 +26,7 @@ class TestJwtFactory {
26
26
 
27
27
  fun createToken(
28
28
  issuer: String = "https://auth.komagu.test/realms/komagu",
29
- audience: String = "komainu-api",
29
+ audience: String = "komagu-api",
30
30
  subject: String? = "alice-100",
31
31
  tenantId: String = "tenant-alpha",
32
32
  issueTime: Instant = Instant.now(),
@@ -27,7 +27,7 @@ class TokenValidationIntegrationTest {
27
27
 
28
28
  companion object {
29
29
  const val EXPECTED_ISSUER = "https://auth.komagu.test/realms/komagu"
30
- const val EXPECTED_AUDIENCE = "komainu-api"
30
+ const val EXPECTED_AUDIENCE = "komagu-api"
31
31
  val jwtFactory = TestJwtFactory()
32
32
  }
33
33
 
@@ -37,7 +37,7 @@
37
37
  ]
38
38
  },
39
39
  {
40
- "clientId": "komainu-api",
40
+ "clientId": "komagu-api",
41
41
  "name": "Komagu Resource Server API",
42
42
  "enabled": true,
43
43
  "bearerOnly": true,
@@ -18,12 +18,12 @@
18
18
  <cfargument name="idValue" type="any" required="true">
19
19
 
20
20
  <cfif isNull(arguments.idValue)>
21
- <cfthrow type="Komainu.InvalidId" message="Identifier cannot be null.">
21
+ <cfthrow type="Komagu.InvalidId" message="Identifier cannot be null.">
22
22
  </cfif>
23
23
 
24
24
  <cfset var s = trim(toString(arguments.idValue))>
25
25
  <cfif len(s) EQ 0 OR NOT reFind("^[1-9][0-9]{0,18}$", s)>
26
- <cfthrow type="Komainu.InvalidId" message="Identifier must be a positive canonical decimal integer.">
26
+ <cfthrow type="Komagu.InvalidId" message="Identifier must be a positive canonical decimal integer.">
27
27
  </cfif>
28
28
 
29
29
  <cfreturn s>
@@ -59,10 +59,10 @@
59
59
  <cfargument name="allowList" type="array" required="true">
60
60
 
61
61
  <cfif NOT arrayFind(arguments.allowList, arguments.identifier)>
62
- <cfthrow type="Komainu.DisallowedIdentifier" message="Disallowed SQL identifier.">
62
+ <cfthrow type="Komagu.DisallowedIdentifier" message="Disallowed SQL identifier.">
63
63
  </cfif>
64
64
  <cfif NOT reFind("^[a-zA-Z_][a-zA-Z0-9_]*$", arguments.identifier)>
65
- <cfthrow type="Komainu.InvalidIdentifier" message="Invalid SQL identifier format.">
65
+ <cfthrow type="Komagu.InvalidIdentifier" message="Invalid SQL identifier format.">
66
66
  </cfif>
67
67
  <cfreturn arguments.identifier>
68
68
  </cffunction>
@@ -99,7 +99,7 @@
99
99
  </cfquery>
100
100
 
101
101
  <cfif qOwnership.recordCount EQ 0>
102
- <cfthrow type="Komainu.AccessDenied" message="Record not found or not owned.">
102
+ <cfthrow type="Komagu.AccessDenied" message="Record not found or not owned.">
103
103
  </cfif>
104
104
 
105
105
  <cfreturn normResId>
@@ -42,7 +42,7 @@ val safeClause = allowList.buildSortClause(userInputColumn, "DESC")
42
42
 
43
43
  The `Komagu.Security.Query.Analyzers` package inspects syntax trees during build time and inside the IDE to flag any string concatenation or string interpolation passed into raw SQL query methods:
44
44
 
45
- - **Diagnostic ID:** `KOMAINU001`
45
+ - **Diagnostic ID:** `KOMAGU001`
46
46
  - **Severity:** `Warning` / `Error`
47
47
  - **Target APIs:** `FromSqlRaw`, `ExecuteSqlRaw`, `ExecuteSqlRawAsync`, `SqlQueryRaw`, `Query`, `Execute`.
48
48
 
@@ -3,5 +3,5 @@ namespace Komagu.Security.Query.Analyzers;
3
3
  public static class DiagnosticIds
4
4
  {
5
5
  // Kept after the rename so existing #pragma / .editorconfig suppressions still apply (#290).
6
- public const string SqlInjectionDiagnosticId = "KOMAINU001";
6
+ public const string SqlInjectionDiagnosticId = "KOMAGU001";
7
7
  }
@@ -10,7 +10,7 @@
10
10
  <Version>1.0.0-preview.1</Version>
11
11
  <Authors>Komagu Contributors</Authors>
12
12
  <Company>Komagu Security</Company>
13
- <Description>Roslyn analyzer rule KOMAINU001 detecting SQL injection from string-built queries in C#.</Description>
13
+ <Description>Roslyn analyzer rule KOMAGU001 detecting SQL injection from string-built queries in C#.</Description>
14
14
  <PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
15
15
  <IsRoslynComponent>true</IsRoslynComponent>
16
16
  <EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
@@ -9,7 +9,7 @@ import io.gitlab.arturbosch.detekt.api.RuleSetProvider
9
9
  */
10
10
  class KomaguRuleSetProvider : RuleSetProvider {
11
11
  // Kept after the rename so existing detekt.yml sections and @Suppress ids still apply (#290).
12
- override val ruleSetId: String = "komainu-security"
12
+ override val ruleSetId: String = "komagu-security"
13
13
 
14
14
  override fun instance(config: Config): RuleSet {
15
15
  return RuleSet(
@@ -15,18 +15,12 @@ import json
15
15
  import os
16
16
  import sys
17
17
  import time
18
- import warnings
19
18
  from typing import Any, Dict, List, Optional, Tuple
20
19
 
21
20
 
22
21
  def _env(name: str, default: Optional[str] = None) -> Optional[str]:
23
- """Read KOMAGU_<name>, falling back to the deprecated KOMAINU_<name> (#290)."""
24
- value = os.environ.get("KOMAGU_" + name)
25
- if value is None:
26
- value = os.environ.get("KOMAINU_" + name)
27
- if value is not None:
28
- warnings.warn(f"KOMAINU_{name} is deprecated, set KOMAGU_{name} instead", DeprecationWarning, stacklevel=2)
29
- return default if value is None else value
22
+ """Read KOMAGU_<name>."""
23
+ return os.environ.get("KOMAGU_" + name, default)
30
24
 
31
25
 
32
26
 
@@ -34,7 +34,7 @@ A Disaster Recovery failover is declared by the Incident Commander / Principal A
34
34
  ### Phase 2: Secondary Cluster Activation (大阪スタンバイ環境起動)
35
35
  1. Scale Osaka ECS tasks from 0 (warm standby) to production capacity:
36
36
  ```bash
37
- aws ecs update-service --cluster komainu-production-standby-dr-cluster \
37
+ aws ecs update-service --cluster komagu-production-standby-dr-cluster \
38
38
  --service api-gateway --desired-count 4 --region ap-northeast-3
39
39
  ```
40
40
  2. Rehydrate relational state from S3 Object Lock Compliance WORM bucket:
@@ -43,7 +43,7 @@ A Disaster Recovery failover is declared by the Incident Commander / Principal A
43
43
  ```
44
44
 
45
45
  ### Phase 3: Route53 Traffic Cutover (DNS切替)
46
- 1. Update DNS failover record to point to Osaka ALB (`osaka-dr-alb.komainu.internal`).
46
+ 1. Update DNS failover record to point to Osaka ALB (`osaka-dr-alb.komagu.internal`).
47
47
  2. Verify smoke test health check returns HTTP 200 on all core endpoints.
48
48
 
49
49
  ---
@@ -15,7 +15,7 @@ variable "secondary_region" {
15
15
  variable "project_name" {
16
16
  description = "Project and workload prefix"
17
17
  type = string
18
- default = "komainu"
18
+ default = "komagu"
19
19
  }
20
20
 
21
21
  variable "environment" {
@@ -17,18 +17,12 @@ import os
17
17
  import secrets
18
18
  import sys
19
19
  import threading
20
- import warnings
21
20
  from typing import Any, Dict, List, Optional, Tuple
22
21
 
23
22
 
24
23
  def _env(name: str, default: Optional[str] = None) -> Optional[str]:
25
- """Read KOMAGU_<name>, falling back to the deprecated KOMAINU_<name> (#290)."""
26
- value = os.environ.get("KOMAGU_" + name)
27
- if value is None:
28
- value = os.environ.get("KOMAINU_" + name)
29
- if value is not None:
30
- warnings.warn(f"KOMAINU_{name} is deprecated, set KOMAGU_{name} instead", DeprecationWarning, stacklevel=2)
31
- return default if value is None else value
24
+ """Read KOMAGU_<name>."""
25
+ return os.environ.get("KOMAGU_" + name, default)
32
26
 
33
27
 
34
28
 
@@ -15,18 +15,12 @@ import json
15
15
  import os
16
16
  import secrets
17
17
  import sys
18
- import warnings
19
18
  from typing import Any, Dict, Optional, Tuple
20
19
 
21
20
 
22
21
  def _env(name: str, default: Optional[str] = None) -> Optional[str]:
23
- """Read KOMAGU_<name>, falling back to the deprecated KOMAINU_<name> (#290)."""
24
- value = os.environ.get("KOMAGU_" + name)
25
- if value is None:
26
- value = os.environ.get("KOMAINU_" + name)
27
- if value is not None:
28
- warnings.warn(f"KOMAINU_{name} is deprecated, set KOMAGU_{name} instead", DeprecationWarning, stacklevel=2)
29
- return default if value is None else value
22
+ """Read KOMAGU_<name>."""
23
+ return os.environ.get("KOMAGU_" + name, default)
30
24
 
31
25
 
32
26
  try:
@@ -12,18 +12,12 @@ from contextlib import contextmanager
12
12
  import hmac
13
13
  import os
14
14
  import re
15
- import warnings
16
15
  from typing import Any, Dict, Iterator, Optional
17
16
 
18
17
 
19
18
  def _env(name: str, default: Optional[str] = None) -> Optional[str]:
20
- """Read KOMAGU_<name>, falling back to the deprecated KOMAINU_<name> (#290)."""
21
- value = os.environ.get("KOMAGU_" + name)
22
- if value is None:
23
- value = os.environ.get("KOMAINU_" + name)
24
- if value is not None:
25
- warnings.warn(f"KOMAINU_{name} is deprecated, set KOMAGU_{name} instead", DeprecationWarning, stacklevel=2)
26
- return default if value is None else value
19
+ """Read KOMAGU_<name>."""
20
+ return os.environ.get("KOMAGU_" + name, default)
27
21
 
28
22
 
29
23
  # Context variable holding the active tenant_id for the current execution thread/coroutine
@@ -8,16 +8,16 @@
8
8
  -- In autocommit connection pools, session state expires immediately after set_current_tenant().
9
9
  -- 2. ROLE RESTRICTION: FORCE ROW LEVEL SECURITY enforces policies on table owners
10
10
  -- and standard users, but NEVER applies to PostgreSQL superusers or roles with BYPASSRLS.
11
- -- Applications MUST connect using a non-owner, non-BYPASSRLS application role (komainu_app).
11
+ -- Applications MUST connect using a non-owner, non-BYPASSRLS application role (komagu_app).
12
12
 
13
13
  -- 0. Provision Dedicated Non-Owner Application Role (without hard-coded password)
14
14
  -- NOTE: In production environments requiring LOGIN connections, configure passwords
15
- -- exclusively via deployment orchestration or vault parameters (ALTER ROLE komainu_app WITH LOGIN PASSWORD ...),
15
+ -- exclusively via deployment orchestration or vault parameters (ALTER ROLE komagu_app WITH LOGIN PASSWORD ...),
16
16
  -- NEVER hard-code credentials in committed migration scripts.
17
17
  DO $$
18
18
  BEGIN
19
- IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'komainu_app') THEN
20
- CREATE ROLE komainu_app WITH NOSUPERUSER NOBYPASSRLS NOCREATEDB NOCREATEROLE NOLOGIN;
19
+ IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'komagu_app') THEN
20
+ CREATE ROLE komagu_app WITH NOSUPERUSER NOBYPASSRLS NOCREATEDB NOCREATEROLE NOLOGIN;
21
21
  END IF;
22
22
  END;
23
23
  $$;
@@ -55,7 +55,7 @@ ALTER TABLE orders FORCE ROW LEVEL SECURITY;
55
55
  DROP POLICY IF EXISTS tenant_org_isolation_policy ON tenant_organizations;
56
56
  CREATE POLICY tenant_org_isolation_policy ON tenant_organizations
57
57
  FOR ALL
58
- TO komainu_app
58
+ TO komagu_app
59
59
  USING (
60
60
  id = NULLIF(current_setting('app.current_tenant_id', true), '')
61
61
  )
@@ -67,7 +67,7 @@ CREATE POLICY tenant_org_isolation_policy ON tenant_organizations
67
67
  DROP POLICY IF EXISTS tenant_isolation_policy ON orders;
68
68
  CREATE POLICY tenant_isolation_policy ON orders
69
69
  FOR ALL
70
- TO komainu_app
70
+ TO komagu_app
71
71
  USING (
72
72
  tenant_id = NULLIF(current_setting('app.current_tenant_id', true), '')
73
73
  )
@@ -126,11 +126,11 @@ CREATE TRIGGER trg_orders_tenant_injection
126
126
 
127
127
  -- 6. Grant Least-Privilege Access to Application Role & Revoke Public Execution
128
128
  REVOKE ALL ON FUNCTION trg_inject_current_tenant() FROM PUBLIC;
129
- GRANT USAGE ON SCHEMA public TO komainu_app;
130
- GRANT SELECT, INSERT, UPDATE, DELETE ON tenant_organizations TO komainu_app;
131
- GRANT SELECT, INSERT, UPDATE, DELETE ON orders TO komainu_app;
129
+ GRANT USAGE ON SCHEMA public TO komagu_app;
130
+ GRANT SELECT, INSERT, UPDATE, DELETE ON tenant_organizations TO komagu_app;
131
+ GRANT SELECT, INSERT, UPDATE, DELETE ON orders TO komagu_app;
132
132
 
133
133
  REVOKE ALL ON FUNCTION set_current_tenant(VARCHAR) FROM PUBLIC;
134
134
  REVOKE ALL ON FUNCTION reset_current_tenant() FROM PUBLIC;
135
- GRANT EXECUTE ON FUNCTION set_current_tenant(VARCHAR) TO komainu_app;
136
- GRANT EXECUTE ON FUNCTION reset_current_tenant() TO komainu_app;
135
+ GRANT EXECUTE ON FUNCTION set_current_tenant(VARCHAR) TO komagu_app;
136
+ GRANT EXECUTE ON FUNCTION reset_current_tenant() TO komagu_app;
@@ -59,10 +59,10 @@ BEGIN
59
59
 
60
60
 
61
61
  -- Grant least-privilege tenant access to application role
62
- IF EXISTS (SELECT 1 FROM pg_catalog.pg_roles WHERE rolname = 'komainu_app') THEN
63
- EXECUTE format('GRANT USAGE ON SCHEMA %I TO komainu_app', v_schema_name);
64
- EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA %I TO komainu_app', v_schema_name);
65
- EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %I GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO komainu_app', v_schema_name);
62
+ IF EXISTS (SELECT 1 FROM pg_catalog.pg_roles WHERE rolname = 'komagu_app') THEN
63
+ EXECUTE format('GRANT USAGE ON SCHEMA %I TO komagu_app', v_schema_name);
64
+ EXECUTE format('GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA %I TO komagu_app', v_schema_name);
65
+ EXECUTE format('ALTER DEFAULT PRIVILEGES IN SCHEMA %I GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO komagu_app', v_schema_name);
66
66
  END IF;
67
67
 
68
68
  END;
@@ -101,11 +101,11 @@ $$ LANGUAGE plpgsql;
101
101
  REVOKE ALL ON FUNCTION create_tenant_schema(VARCHAR) FROM PUBLIC;
102
102
  REVOKE ALL ON FUNCTION switch_tenant_schema(VARCHAR) FROM PUBLIC;
103
103
  REVOKE ALL ON TABLE public.tenant_registry FROM PUBLIC;
104
- -- Note: No SELECT grant on tenant_registry for komainu_app. Namespace‑only isolation is enforced; cross‑tenant queries must use tenant‑specific schemas.
104
+ -- Note: No SELECT grant on tenant_registry for komagu_app. Namespace‑only isolation is enforced; cross‑tenant queries must use tenant‑specific schemas.
105
105
  DO $$
106
106
  BEGIN
107
- IF EXISTS (SELECT 1 FROM pg_catalog.pg_roles WHERE rolname = 'komainu_app') THEN
108
- GRANT EXECUTE ON FUNCTION switch_tenant_schema(VARCHAR) TO komainu_app;
107
+ IF EXISTS (SELECT 1 FROM pg_catalog.pg_roles WHERE rolname = 'komagu_app') THEN
108
+ GRANT EXECUTE ON FUNCTION switch_tenant_schema(VARCHAR) TO komagu_app;
109
109
  END IF;
110
110
  END $$;
111
111
 
@@ -16,7 +16,7 @@ import psycopg2
16
16
  from psycopg2 import sql
17
17
 
18
18
  # Paths to the SQL scripts relative to the repository root.
19
- REPO_ROOT = Path("/Users/hoanghainh/Projects/komainu")
19
+ REPO_ROOT = Path(__file__).resolve().parents[2]
20
20
  SCHEMA_SQL = REPO_ROOT / "remediate" / "tenancy" / "sql" / "schema_per_tenant.sql"
21
21
  RLS_SQL = REPO_ROOT / "remediate" / "tenancy" / "sql" / "rls_isolation.sql"
22
22
 
@@ -206,8 +206,8 @@ class TestTenantIsolationAndBYOK(unittest.TestCase):
206
206
  self.assertIn("REVOKE ALL ON ALL TABLES IN SCHEMA %I FROM PUBLIC", sql_content)
207
207
  self.assertIn("REVOKE ALL ON FUNCTION create_tenant_schema(VARCHAR) FROM PUBLIC", sql_content)
208
208
  self.assertIn("REVOKE ALL ON FUNCTION switch_tenant_schema(VARCHAR) FROM PUBLIC", sql_content)
209
- self.assertIn("GRANT USAGE ON SCHEMA %I TO komainu_app", sql_content)
210
- self.assertIn("GRANT EXECUTE ON FUNCTION switch_tenant_schema(VARCHAR) TO komainu_app", sql_content)
209
+ self.assertIn("GRANT USAGE ON SCHEMA %I TO komagu_app", sql_content)
210
+ self.assertIn("GRANT EXECUTE ON FUNCTION switch_tenant_schema(VARCHAR) TO komagu_app", sql_content)
211
211
 
212
212
  def test_11_rls_sql_app_role_and_tenant_organizations_security(self) -> None:
213
213
  """Verifies RLS template defines non-owner app role, protects tenant_organizations, and pins search_path."""
@@ -215,7 +215,7 @@ class TestTenantIsolationAndBYOK(unittest.TestCase):
215
215
  with open(rls_file, "r", encoding="utf-8") as f:
216
216
  sql_content = f.read()
217
217
 
218
- self.assertIn("CREATE ROLE komainu_app WITH NOSUPERUSER NOBYPASSRLS", sql_content)
218
+ self.assertIn("CREATE ROLE komagu_app WITH NOSUPERUSER NOBYPASSRLS", sql_content)
219
219
  self.assertIn("NOLOGIN", sql_content)
220
220
  self.assertNotIn("replace_with_secure_app_password", sql_content)
221
221
  self.assertIn("ALTER TABLE tenant_organizations ENABLE ROW LEVEL SECURITY", sql_content)
@@ -225,7 +225,7 @@ class TestTenantIsolationAndBYOK(unittest.TestCase):
225
225
  self.assertIn("TRANSACTION REQUIREMENT", sql_content)
226
226
  self.assertIn("BEGIN ... COMMIT", sql_content)
227
227
  self.assertIn("REVOKE ALL ON FUNCTION set_current_tenant(VARCHAR) FROM PUBLIC", sql_content)
228
- self.assertIn("GRANT EXECUTE ON FUNCTION set_current_tenant(VARCHAR) TO komainu_app", sql_content)
228
+ self.assertIn("GRANT EXECUTE ON FUNCTION set_current_tenant(VARCHAR) TO komagu_app", sql_content)
229
229
 
230
230
  def test_12_rls_cross_tenant_isolation_logic_simulation(self) -> None:
231
231
  """Simulates RLS policy evaluation: verifying cross-tenant records cannot be read."""
package/bin/komainu DELETED
@@ -1,16 +0,0 @@
1
- #!/usr/bin/env python3
2
- """Deprecated `bin/komainu` entrypoint: use `bin/komagu` (#290)."""
3
-
4
- from __future__ import annotations
5
-
6
- import sys
7
- from pathlib import Path
8
-
9
- REPO_ROOT = Path(__file__).resolve().parent.parent
10
- sys.path.insert(0, str(REPO_ROOT))
11
-
12
- from operate.cli.main import main # noqa: E402
13
-
14
- if __name__ == "__main__":
15
- print("[DEPRECATED] bin/komainu was renamed to bin/komagu.", file=sys.stderr)
16
- sys.exit(main())
@@ -1,16 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Deprecated `komainu` / `komainu-guard` npm bin aliases.
4
- *
5
- * Prints a rename notice to stderr, then runs the Komagu launcher unchanged.
6
- * Remove in the next major release (#290).
7
- */
8
-
9
- 'use strict';
10
-
11
- console.error(
12
- '\x1b[33m[DEPRECATED]\x1b[0m `komainu` / `komainu-guard` were renamed to `komagu`. ' +
13
- 'Install @hoanghainh/komagu and run `komagu` instead.'
14
- );
15
-
16
- require('./komagu.js');
@@ -1,33 +0,0 @@
1
- #!/usr/bin/env python3
2
- """KOMAGU_* environment variables with the deprecated KOMAINU_* fallback (#290)."""
3
-
4
- from __future__ import annotations
5
-
6
- import os
7
- import unittest
8
- import warnings
9
- from unittest.mock import patch
10
-
11
- from remediate.ekyc.server import tokenization, jpki_verifier
12
-
13
- MODULES = (tokenization, jpki_verifier)
14
-
15
-
16
- class TestLegacyEnvFallback(unittest.TestCase):
17
- def test_new_name_wins_without_warning(self) -> None:
18
- env = {"KOMAGU_EKYC_HMAC_KEY": "new", "KOMAINU_EKYC_HMAC_KEY": "old"}
19
- for mod in MODULES:
20
- with self.subTest(module=mod.__name__), patch.dict(os.environ, env), warnings.catch_warnings(record=True) as caught:
21
- warnings.simplefilter("always")
22
- self.assertEqual(mod._env("EKYC_HMAC_KEY"), "new")
23
- self.assertEqual(caught, [])
24
-
25
- def test_legacy_name_is_read_with_deprecation_warning(self) -> None:
26
- for mod in MODULES:
27
- with self.subTest(module=mod.__name__), patch.dict(os.environ, {"KOMAINU_EKYC_HMAC_KEY": "old"}, clear=True):
28
- with self.assertWarnsRegex(DeprecationWarning, "KOMAINU_EKYC_HMAC_KEY is deprecated"):
29
- self.assertEqual(mod._env("EKYC_HMAC_KEY"), "old")
30
-
31
-
32
- if __name__ == "__main__":
33
- unittest.main()
@@ -1,33 +0,0 @@
1
- #!/usr/bin/env python3
2
- """KOMAGU_* environment variables with the deprecated KOMAINU_* fallback (#290)."""
3
-
4
- from __future__ import annotations
5
-
6
- import os
7
- import unittest
8
- import warnings
9
- from unittest.mock import patch
10
-
11
- from remediate.identity.python.komagu_identity import oidc_validator
12
-
13
- MODULES = (oidc_validator,)
14
-
15
-
16
- class TestLegacyEnvFallback(unittest.TestCase):
17
- def test_new_name_wins_without_warning(self) -> None:
18
- env = {"KOMAGU_ALLOW_DEV_TOKENS": "new", "KOMAINU_ALLOW_DEV_TOKENS": "old"}
19
- for mod in MODULES:
20
- with self.subTest(module=mod.__name__), patch.dict(os.environ, env), warnings.catch_warnings(record=True) as caught:
21
- warnings.simplefilter("always")
22
- self.assertEqual(mod._env("ALLOW_DEV_TOKENS"), "new")
23
- self.assertEqual(caught, [])
24
-
25
- def test_legacy_name_is_read_with_deprecation_warning(self) -> None:
26
- for mod in MODULES:
27
- with self.subTest(module=mod.__name__), patch.dict(os.environ, {"KOMAINU_ALLOW_DEV_TOKENS": "old"}, clear=True):
28
- with self.assertWarnsRegex(DeprecationWarning, "KOMAINU_ALLOW_DEV_TOKENS is deprecated"):
29
- self.assertEqual(mod._env("ALLOW_DEV_TOKENS"), "old")
30
-
31
-
32
- if __name__ == "__main__":
33
- unittest.main()