fix tests. new product advisories enhancements
This commit is contained in:
@@ -664,24 +664,24 @@ CREATE TABLE IF NOT EXISTS policy.budget_ledger (
|
||||
service_id VARCHAR(128) NOT NULL,
|
||||
tenant_id VARCHAR(64),
|
||||
tier INT NOT NULL DEFAULT 1,
|
||||
window VARCHAR(16) NOT NULL,
|
||||
"window" VARCHAR(16) NOT NULL,
|
||||
allocated INT NOT NULL,
|
||||
consumed INT NOT NULL DEFAULT 0,
|
||||
status VARCHAR(16) NOT NULL DEFAULT 'green',
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
CONSTRAINT uq_budget_ledger_service_window UNIQUE (service_id, window)
|
||||
CONSTRAINT uq_budget_ledger_service_window UNIQUE (service_id, "window")
|
||||
);
|
||||
|
||||
CREATE INDEX idx_budget_ledger_service_id ON policy.budget_ledger (service_id);
|
||||
CREATE INDEX idx_budget_ledger_tenant_id ON policy.budget_ledger (tenant_id);
|
||||
CREATE INDEX idx_budget_ledger_window ON policy.budget_ledger (window);
|
||||
CREATE INDEX idx_budget_ledger_window ON policy.budget_ledger ("window");
|
||||
CREATE INDEX idx_budget_ledger_status ON policy.budget_ledger (status);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS policy.budget_entries (
|
||||
entry_id VARCHAR(64) PRIMARY KEY,
|
||||
service_id VARCHAR(128) NOT NULL,
|
||||
window VARCHAR(16) NOT NULL,
|
||||
"window" VARCHAR(16) NOT NULL,
|
||||
release_id VARCHAR(128) NOT NULL,
|
||||
risk_points INT NOT NULL,
|
||||
reason VARCHAR(512),
|
||||
@@ -689,11 +689,11 @@ CREATE TABLE IF NOT EXISTS policy.budget_entries (
|
||||
penalty_points INT NOT NULL DEFAULT 0,
|
||||
consumed_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
consumed_by VARCHAR(256),
|
||||
CONSTRAINT fk_budget_entries_ledger FOREIGN KEY (service_id, window)
|
||||
REFERENCES policy.budget_ledger (service_id, window) ON DELETE CASCADE
|
||||
CONSTRAINT fk_budget_entries_ledger FOREIGN KEY (service_id, "window")
|
||||
REFERENCES policy.budget_ledger (service_id, "window") ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE INDEX idx_budget_entries_service_window ON policy.budget_entries (service_id, window);
|
||||
CREATE INDEX idx_budget_entries_service_window ON policy.budget_entries (service_id, "window");
|
||||
CREATE INDEX idx_budget_entries_release_id ON policy.budget_entries (release_id);
|
||||
CREATE INDEX idx_budget_entries_consumed_at ON policy.budget_entries (consumed_at);
|
||||
|
||||
@@ -1219,7 +1219,7 @@ CREATE POLICY budget_entries_tenant_isolation ON policy.budget_entries
|
||||
EXISTS (
|
||||
SELECT 1 FROM policy.budget_ledger bl
|
||||
WHERE bl.service_id = budget_entries.service_id
|
||||
AND bl.window = budget_entries.window
|
||||
AND bl."window" = budget_entries."window"
|
||||
AND (bl.tenant_id = current_setting('app.tenant_id', TRUE) OR bl.tenant_id IS NULL)
|
||||
)
|
||||
);
|
||||
|
||||
@@ -106,10 +106,10 @@ CREATE INDEX IF NOT EXISTS idx_gate_bypass_audit_image_digest
|
||||
CREATE INDEX IF NOT EXISTS idx_gate_bypass_audit_bypass_type
|
||||
ON policy.gate_bypass_audit(tenant_id, bypass_type);
|
||||
|
||||
-- Partial index for active time-limited bypasses
|
||||
CREATE INDEX IF NOT EXISTS idx_gate_bypass_audit_active_bypasses
|
||||
ON policy.gate_bypass_audit(tenant_id, expires_at)
|
||||
WHERE expires_at IS NOT NULL AND expires_at > NOW();
|
||||
-- Partial index for time-limited bypasses (filtered by non-null expires_at)
|
||||
CREATE INDEX IF NOT EXISTS idx_gate_bypass_audit_active_bypasses
|
||||
ON policy.gate_bypass_audit(tenant_id, expires_at)
|
||||
WHERE expires_at IS NOT NULL;
|
||||
|
||||
-- ============================================================================
|
||||
-- Row Level Security (RLS) Policies
|
||||
|
||||
@@ -31,6 +31,11 @@ public sealed class ExceptionEntity
|
||||
/// </summary>
|
||||
public required Guid Id { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Human-readable unique exception identifier.
|
||||
/// </summary>
|
||||
public string ExceptionId { get; init; } = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Tenant identifier.
|
||||
/// </summary>
|
||||
|
||||
@@ -23,11 +23,11 @@ public sealed class ExceptionRepository : RepositoryBase<PolicyDataSource>, IExc
|
||||
{
|
||||
const string sql = """
|
||||
INSERT INTO policy.exceptions (
|
||||
id, tenant_id, name, description, rule_pattern, resource_pattern,
|
||||
id, exception_id, tenant_id, name, description, rule_pattern, resource_pattern,
|
||||
artifact_pattern, project_id, reason, status, expires_at, metadata, created_by
|
||||
)
|
||||
VALUES (
|
||||
@id, @tenant_id, @name, @description, @rule_pattern, @resource_pattern,
|
||||
@id, @exception_id, @tenant_id, @name, @description, @rule_pattern, @resource_pattern,
|
||||
@artifact_pattern, @project_id, @reason, @status, @expires_at, @metadata::jsonb, @created_by
|
||||
)
|
||||
RETURNING *
|
||||
@@ -295,6 +295,11 @@ public sealed class ExceptionRepository : RepositoryBase<PolicyDataSource>, IExc
|
||||
private static void AddExceptionParameters(NpgsqlCommand command, ExceptionEntity exception)
|
||||
{
|
||||
AddParameter(command, "id", exception.Id);
|
||||
// Generate exception_id from Id if not provided
|
||||
var exceptionId = string.IsNullOrEmpty(exception.ExceptionId)
|
||||
? $"exc-{exception.Id:N}"[..24]
|
||||
: exception.ExceptionId;
|
||||
AddParameter(command, "exception_id", exceptionId);
|
||||
AddParameter(command, "tenant_id", exception.TenantId);
|
||||
AddParameter(command, "name", exception.Name);
|
||||
AddParameter(command, "description", exception.Description);
|
||||
@@ -312,6 +317,7 @@ public sealed class ExceptionRepository : RepositoryBase<PolicyDataSource>, IExc
|
||||
private static ExceptionEntity MapException(NpgsqlDataReader reader) => new()
|
||||
{
|
||||
Id = reader.GetGuid(reader.GetOrdinal("id")),
|
||||
ExceptionId = reader.GetString(reader.GetOrdinal("exception_id")),
|
||||
TenantId = reader.GetString(reader.GetOrdinal("tenant_id")),
|
||||
Name = reader.GetString(reader.GetOrdinal("name")),
|
||||
Description = GetNullableString(reader, reader.GetOrdinal("description")),
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Migrations\**\*.sql" LogicalName="%(RecursiveDir)%(Filename)%(Extension)" />
|
||||
<EmbeddedResource Include="Migrations\*.sql" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -386,12 +386,18 @@ public sealed class SignatureRequiredGate : IPolicyGate
|
||||
if (trusted.StartsWith("*@", StringComparison.Ordinal))
|
||||
{
|
||||
var domain = trusted[2..];
|
||||
if (issuer.EndsWith($"@{domain}", StringComparison.OrdinalIgnoreCase))
|
||||
if (!domain.Contains('*'))
|
||||
{
|
||||
return true;
|
||||
// Simple wildcard: *@domain.com matches any local part with exact domain
|
||||
if (issuer.EndsWith($"@{domain}", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else if (trusted.Contains('*'))
|
||||
|
||||
if (trusted.Contains('*'))
|
||||
{
|
||||
// General wildcard pattern
|
||||
var pattern = "^" + Regex.Escape(trusted).Replace("\\*", ".*") + "$";
|
||||
|
||||
Reference in New Issue
Block a user