diff --git a/README.md b/README.md index 728b8d0..9d46480 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # GovOPlaN IDM + +**Repository type:** module (platform). + + `govoplan-idm` is the planned integration module for external identity management systems. It does not own GovOPlaN's internal identity, organization, account, role, or tenant tables; those remain with `govoplan-identity`, diff --git a/package.json b/package.json index e163513..adcdb36 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@govoplan/idm-webui", - "version": "0.1.7", + "version": "0.1.8", "private": true, "type": "module", "main": "webui/src/index.ts", @@ -19,7 +19,7 @@ "LICENSE" ], "peerDependencies": { - "@govoplan/core-webui": "^0.1.7", + "@govoplan/core-webui": "^0.1.8", "@vitejs/plugin-react": "^4.3.4", "lucide-react": "^1.23.0", "react": "^19.0.0", diff --git a/pyproject.toml b/pyproject.toml index 6648d25..83d7392 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,15 +4,15 @@ build-backend = "setuptools.build_meta" [project] name = "govoplan-idm" -version = "0.1.7" +version = "0.1.8" description = "GovOPlaN identity management bridge module." readme = "README.md" requires-python = ">=3.12" authors = [{ name = "GovOPlaN" }] dependencies = [ - "govoplan-core>=0.1.7", - "govoplan-identity>=0.1.7", - "govoplan-organizations>=0.1.7", + "govoplan-core>=0.1.8", + "govoplan-identity>=0.1.8", + "govoplan-organizations>=0.1.8", ] [tool.setuptools.packages.find] diff --git a/src/govoplan_idm/backend/manifest.py b/src/govoplan_idm/backend/manifest.py index 4012964..de39d49 100644 --- a/src/govoplan_idm/backend/manifest.py +++ b/src/govoplan_idm/backend/manifest.py @@ -102,7 +102,7 @@ def _idm_directory(context: ModuleContext) -> object: manifest = ModuleManifest( id="idm", name="IDM", - version="0.1.7", + version="0.1.8", dependencies=("identity", "organizations"), optional_dependencies=("access", "audit"), required_capabilities=(CAPABILITY_AUTH_PRINCIPAL_RESOLVER, CAPABILITY_AUTH_PERMISSION_EVALUATOR), diff --git a/src/govoplan_idm/backend/migrations/versions/8f9a0b1c2d3e_idm_organization_function_assignments.py b/src/govoplan_idm/backend/migrations/dev_versions/8f9a0b1c2d3e_idm_organization_function_assignments.py similarity index 100% rename from src/govoplan_idm/backend/migrations/versions/8f9a0b1c2d3e_idm_organization_function_assignments.py rename to src/govoplan_idm/backend/migrations/dev_versions/8f9a0b1c2d3e_idm_organization_function_assignments.py diff --git a/src/govoplan_idm/backend/migrations/dev_versions/__init__.py b/src/govoplan_idm/backend/migrations/dev_versions/__init__.py new file mode 100644 index 0000000..cd968b7 --- /dev/null +++ b/src/govoplan_idm/backend/migrations/dev_versions/__init__.py @@ -0,0 +1 @@ +"""IDM migration revisions.""" diff --git a/src/govoplan_idm/backend/migrations/versions/8f9a0b1c2d3e_v017_idm_baseline.py b/src/govoplan_idm/backend/migrations/versions/8f9a0b1c2d3e_v017_idm_baseline.py new file mode 100644 index 0000000..72c211d --- /dev/null +++ b/src/govoplan_idm/backend/migrations/versions/8f9a0b1c2d3e_v017_idm_baseline.py @@ -0,0 +1,65 @@ +"""v0.1.7 idm baseline + +Revision ID: 8f9a0b1c2d3e +Revises: None +Create Date: 2026-07-11 00:00:00.000000 +""" +from __future__ import annotations + +from alembic import op +import sqlalchemy as sa + + +revision = '8f9a0b1c2d3e' +down_revision = None +branch_labels = None +depends_on = ('5c6d7e8f9a10', '6d7e8f9a0b1c') + + +def upgrade() -> None: + op.create_table('idm_tenant_settings', + sa.Column('tenant_id', sa.String(length=36), nullable=False), + sa.Column('require_assignment_change_requests', sa.Boolean(), nullable=False), + sa.Column('audit_detail_level', sa.String(length=20), nullable=False), + sa.Column('change_retention_days', sa.Integer(), nullable=True), + sa.Column('settings', sa.JSON(), nullable=False), + sa.Column('created_at', sa.DateTime(timezone=True), nullable=False), + sa.Column('updated_at', sa.DateTime(timezone=True), nullable=False), + sa.PrimaryKeyConstraint('tenant_id', name=op.f('pk_idm_tenant_settings')) + ) + op.create_table('idm_organization_function_assignments', + sa.Column('id', sa.String(length=36), nullable=False), + sa.Column('tenant_id', sa.String(length=36), nullable=False), + sa.Column('identity_id', sa.String(length=36), nullable=False), + sa.Column('account_id', sa.String(length=36), nullable=True), + sa.Column('function_id', sa.String(length=36), nullable=False), + sa.Column('organization_unit_id', sa.String(length=36), nullable=False), + sa.Column('applies_to_subunits', sa.Boolean(), nullable=False), + sa.Column('source', sa.String(length=50), nullable=False), + sa.Column('delegated_from_assignment_id', sa.String(length=36), nullable=True), + sa.Column('acting_for_account_id', sa.String(length=36), nullable=True), + sa.Column('valid_from', sa.DateTime(timezone=True), nullable=True), + sa.Column('valid_until', sa.DateTime(timezone=True), nullable=True), + sa.Column('is_active', sa.Boolean(), nullable=False), + sa.Column('settings', sa.JSON(), nullable=False), + sa.Column('created_at', sa.DateTime(timezone=True), nullable=False), + sa.Column('updated_at', sa.DateTime(timezone=True), nullable=False), + sa.ForeignKeyConstraint(['delegated_from_assignment_id'], ['idm_organization_function_assignments.id'], name=op.f('fk_idm_organization_function_assignments_delegated_from_assignment_id_idm_organization_function_assignments'), ondelete='SET NULL'), + sa.ForeignKeyConstraint(['function_id'], ['organizations_functions.id'], name=op.f('fk_idm_organization_function_assignments_function_id_organizations_functions'), ondelete='CASCADE'), + sa.ForeignKeyConstraint(['identity_id'], ['identity_identities.id'], name=op.f('fk_idm_organization_function_assignments_identity_id_identity_identities'), ondelete='CASCADE'), + sa.ForeignKeyConstraint(['organization_unit_id'], ['organizations_units.id'], name=op.f('fk_idm_organization_function_assignments_organization_unit_id_organizations_units'), ondelete='CASCADE'), + sa.PrimaryKeyConstraint('id', name=op.f('pk_idm_organization_function_assignments')), + sa.UniqueConstraint('tenant_id', 'identity_id', 'function_id', 'organization_unit_id', name='uq_idm_org_function_assignments_identity_scope') + ) + op.create_index(op.f('ix_idm_organization_function_assignments_account_id'), 'idm_organization_function_assignments', ['account_id'], unique=False) + op.create_index(op.f('ix_idm_organization_function_assignments_acting_for_account_id'), 'idm_organization_function_assignments', ['acting_for_account_id'], unique=False) + op.create_index(op.f('ix_idm_organization_function_assignments_delegated_from_assignment_id'), 'idm_organization_function_assignments', ['delegated_from_assignment_id'], unique=False) + op.create_index(op.f('ix_idm_organization_function_assignments_function_id'), 'idm_organization_function_assignments', ['function_id'], unique=False) + op.create_index(op.f('ix_idm_organization_function_assignments_identity_id'), 'idm_organization_function_assignments', ['identity_id'], unique=False) + op.create_index(op.f('ix_idm_organization_function_assignments_organization_unit_id'), 'idm_organization_function_assignments', ['organization_unit_id'], unique=False) + op.create_index(op.f('ix_idm_organization_function_assignments_tenant_id'), 'idm_organization_function_assignments', ['tenant_id'], unique=False) + + +def downgrade() -> None: + op.drop_table('idm_organization_function_assignments') + op.drop_table('idm_tenant_settings') diff --git a/webui/package.json b/webui/package.json index f8eda85..6291493 100644 --- a/webui/package.json +++ b/webui/package.json @@ -1,6 +1,6 @@ { "name": "@govoplan/idm-webui", - "version": "0.1.7", + "version": "0.1.8", "private": true, "type": "module", "main": "src/index.ts", @@ -14,7 +14,7 @@ "./styles/idm.css": "./src/styles/idm.css" }, "peerDependencies": { - "@govoplan/core-webui": "^0.1.7", + "@govoplan/core-webui": "^0.1.8", "@vitejs/plugin-react": "^4.3.4", "lucide-react": "^1.23.0", "react": "^19.0.0",