Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
447 changes: 422 additions & 25 deletions platform-api/api/generated.go

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions platform-api/internal/apperror/catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,12 @@ var (
ApplicationExists = def(CodeApplicationExists, http.StatusConflict, "An application with this name already exists.")
)

// API Portal entries.
var (
APIPortalNotFound = def(CodeAPIPortalNotFound, http.StatusNotFound, "The specified API Portal could not be found.")
APIPortalExists = def(CodeAPIPortalExists, http.StatusConflict, "An API Portal with this handle already exists in the organization.")
)

// Subscription entries.
var (
SubscriptionNotFound = def(CodeSubscriptionNotFound, http.StatusNotFound, "The specified subscription could not be found.")
Expand Down
6 changes: 6 additions & 0 deletions platform-api/internal/apperror/codes.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,12 @@ const (
CodeApplicationExists = "APPLICATION_EXISTS"
)

// API Portal domain codes.
const (
CodeAPIPortalNotFound = "API_PORTAL_NOT_FOUND"
CodeAPIPortalExists = "API_PORTAL_EXISTS"
)

// Subscription domain codes.
const (
CodeSubscriptionNotFound = "SUBSCRIPTION_NOT_FOUND"
Expand Down
61 changes: 61 additions & 0 deletions platform-api/internal/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,67 @@ var ValidGatewayTokenStatuses = map[string]bool{
GatewayTokenStatusRevoked: true,
}

// API Portal workflow status constants
const (
APIPortalWorkflowStatusPending = "pending"
APIPortalWorkflowStatusActive = "active"
APIPortalWorkflowStatusFailed = "failed"
)

// ValidAPIPortalWorkflowStatuses holds accepted values for api_portals.workflow_status
var ValidAPIPortalWorkflowStatuses = map[string]bool{
APIPortalWorkflowStatusPending: true,
APIPortalWorkflowStatusActive: true,
APIPortalWorkflowStatusFailed: true,
}

// ValidAPIPortalCreateWorkflowStatuses holds accepted values for workflow_status
// at Create time. `failed` is intentionally excluded — a portal is never
// created in a failed state; that state is only reachable via a subsequent
// update once provisioning or a health check reports failure.
var ValidAPIPortalCreateWorkflowStatuses = map[string]bool{
APIPortalWorkflowStatusPending: true,
APIPortalWorkflowStatusActive: true,
}

// API Portal authConfig field-name constants used by Create/Update validation
// (required-field check) and by ClientCredentialsAuthProvider (payload build).
const (
APIPortalAuthConfigKeySTSTokenURL = "stsTokenUrl"
APIPortalAuthConfigKeyClientID = "clientId"
APIPortalAuthConfigKeyClientSecret = "clientSecret"
)

// APIPortalOAuth2RequiredAuthConfigKeys are the keys the oauth2 flow must
// supply in authConfig at Create time (or on Update when auth_type is being
// changed to oauth2). Order is stable so validation error messages list
// missing fields in a predictable sequence.
var APIPortalOAuth2RequiredAuthConfigKeys = []string{
APIPortalAuthConfigKeySTSTokenURL,
APIPortalAuthConfigKeyClientID,
APIPortalAuthConfigKeyClientSecret,
}

// APIPortalAuthConfigSensitiveKeys lists the authConfig keys whose values are
// treated as secrets: encrypted at rest via the platform vault and stripped
// from any response. Independent of auth_type — the set is small and the
// keys are the same shape across types.
var APIPortalAuthConfigSensitiveKeys = []string{
APIPortalAuthConfigKeyClientSecret,
}

// API Portal auth type constants
const (
APIPortalAuthTypeLocal = "local"
APIPortalAuthTypeOAuth2 = "oauth2"
)

// ValidAPIPortalAuthTypes holds accepted values for api_portals.auth_type
var ValidAPIPortalAuthTypes = map[string]bool{
APIPortalAuthTypeLocal: true,
APIPortalAuthTypeOAuth2: true,
}

// ValidArtifactKinds holds accepted values for artifacts.type for the core (non-plugin)
// artifact kinds. Plugin-owned kinds (e.g. WebSubApi, WebBrokerApi) are registered
// into the ArtifactTableRegistry during plugin Init.
Expand Down
21 changes: 21 additions & 0 deletions platform-api/internal/database/schema.postgres.sql
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,26 @@ CREATE TABLE IF NOT EXISTS mcp_proxies (
UNIQUE(organization_uuid, handle)
);

-- API Portals table (registration of an API Portal instance for an organization)
CREATE TABLE IF NOT EXISTS api_portals (
uuid VARCHAR(40) PRIMARY KEY,
organization_uuid VARCHAR(40) NOT NULL,
handle VARCHAR(40) NOT NULL,
display_name VARCHAR(255) NOT NULL,
description VARCHAR(1023),
url VARCHAR(500),
workflow_status VARCHAR(20) NOT NULL DEFAULT 'pending',
auth_type VARCHAR(20) NOT NULL,
auth_configuration BYTEA NOT NULL,
metadata BYTEA NOT NULL,
created_by VARCHAR(200),
created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
updated_by VARCHAR(200),
updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (organization_uuid) REFERENCES organizations(uuid) ON DELETE CASCADE,
UNIQUE (organization_uuid, handle)
);


CREATE TABLE IF NOT EXISTS api_keys (
uuid VARCHAR(40) PRIMARY KEY,
Expand Down Expand Up @@ -473,6 +493,7 @@ CREATE INDEX IF NOT EXISTS idx_llm_proxies_provider_uuid ON llm_proxies(provider
CREATE INDEX IF NOT EXISTS idx_llm_proxies_org ON llm_proxies(organization_uuid);
CREATE INDEX IF NOT EXISTS idx_mcp_proxies_project ON mcp_proxies(project_uuid);
CREATE INDEX IF NOT EXISTS idx_mcp_proxies_org ON mcp_proxies(organization_uuid);
CREATE INDEX IF NOT EXISTS idx_api_portals_org ON api_portals(organization_uuid);
CREATE INDEX IF NOT EXISTS idx_api_keys_artifact ON api_keys(artifact_uuid);
CREATE INDEX IF NOT EXISTS idx_applications_org ON applications(organization_uuid);
CREATE INDEX IF NOT EXISTS idx_applications_project_id ON applications(organization_uuid, project_uuid);
Expand Down
21 changes: 21 additions & 0 deletions platform-api/internal/database/schema.sqlite.sql
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,26 @@ CREATE TABLE IF NOT EXISTS mcp_proxies (
UNIQUE(organization_uuid, handle)
);

-- API Portals table (registration of an API Portal instance for an organization)
CREATE TABLE IF NOT EXISTS api_portals (
uuid VARCHAR(40) PRIMARY KEY,
organization_uuid VARCHAR(40) NOT NULL,
handle VARCHAR(40) NOT NULL,
display_name VARCHAR(255) NOT NULL,
description VARCHAR(1023),
url VARCHAR(500),
workflow_status VARCHAR(20) NOT NULL DEFAULT 'pending',
auth_type VARCHAR(20) NOT NULL,
auth_configuration BLOB NOT NULL,
metadata BLOB NOT NULL,
created_by VARCHAR(200),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_by VARCHAR(200),
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (organization_uuid) REFERENCES organizations(uuid) ON DELETE CASCADE,
UNIQUE (organization_uuid, handle)
);

-- API Keys table (stores API keys for artifacts with hashes as JSON string)
CREATE TABLE IF NOT EXISTS api_keys (
uuid VARCHAR(40) PRIMARY KEY,
Expand Down Expand Up @@ -472,6 +492,7 @@ CREATE INDEX IF NOT EXISTS idx_llm_proxies_provider_uuid ON llm_proxies(provider
CREATE INDEX IF NOT EXISTS idx_llm_proxies_org ON llm_proxies(organization_uuid);
CREATE INDEX IF NOT EXISTS idx_mcp_proxies_project ON mcp_proxies(project_uuid);
CREATE INDEX IF NOT EXISTS idx_mcp_proxies_org ON mcp_proxies(organization_uuid);
CREATE INDEX IF NOT EXISTS idx_api_portals_org ON api_portals(organization_uuid);
CREATE INDEX IF NOT EXISTS idx_api_keys_artifact ON api_keys(artifact_uuid);
CREATE INDEX IF NOT EXISTS idx_rest_apis_org ON rest_apis(organization_uuid);
CREATE INDEX IF NOT EXISTS idx_applications_org ON applications(organization_uuid);
Expand Down
23 changes: 23 additions & 0 deletions platform-api/internal/database/schema.sqlserver.sql
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,27 @@ CREATE TABLE dbo.mcp_proxies (
UNIQUE(organization_uuid, handle)
);

-- API Portals table (registration of an API Portal instance for an organization)
IF OBJECT_ID(N'dbo.api_portals', N'U') IS NULL
CREATE TABLE dbo.api_portals (
uuid VARCHAR(40) PRIMARY KEY,
organization_uuid VARCHAR(40) NOT NULL,
handle VARCHAR(40) NOT NULL,
display_name VARCHAR(255) NOT NULL,
description VARCHAR(1023),
url VARCHAR(500),
workflow_status VARCHAR(20) NOT NULL DEFAULT 'pending',
auth_type VARCHAR(20) NOT NULL,
auth_configuration VARBINARY(MAX) NOT NULL,
metadata VARBINARY(MAX) NOT NULL,
created_by VARCHAR(200),
created_at DATETIME2(7) DEFAULT SYSUTCDATETIME(),
updated_by VARCHAR(200),
updated_at DATETIME2(7) DEFAULT SYSUTCDATETIME(),
FOREIGN KEY (organization_uuid) REFERENCES organizations(uuid) ON DELETE CASCADE,
UNIQUE (organization_uuid, handle)
);

IF OBJECT_ID(N'dbo.api_keys', N'U') IS NULL
CREATE TABLE dbo.api_keys (
uuid VARCHAR(40) PRIMARY KEY,
Expand Down Expand Up @@ -554,6 +575,8 @@ IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'idx_mcp_proxies_project'
CREATE INDEX idx_mcp_proxies_project ON dbo.mcp_proxies(project_uuid);
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'idx_mcp_proxies_org' AND object_id = OBJECT_ID(N'dbo.mcp_proxies'))
CREATE INDEX idx_mcp_proxies_org ON dbo.mcp_proxies(organization_uuid);
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'idx_api_portals_org' AND object_id = OBJECT_ID(N'dbo.api_portals'))
CREATE INDEX idx_api_portals_org ON dbo.api_portals(organization_uuid);
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'idx_api_keys_artifact' AND object_id = OBJECT_ID(N'dbo.api_keys'))
CREATE INDEX idx_api_keys_artifact ON dbo.api_keys(artifact_uuid);
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = N'idx_api_keys_status' AND object_id = OBJECT_ID(N'dbo.api_keys'))
Expand Down
Loading
Loading