"""publisher identity App-local publisher tokens (DR-3, resolved 2026-07-10: app-local accounts with platform OIDC demand-gated; business-app-service-contract sections 2.1-2.2). Tokens are stored hashed. Revocation is a timestamp, and index entries record a publisher *name*, so attribution outlives the credential that produced it. Revision ID: 0003 Revises: 0002 """ from alembic import op import sqlalchemy as sa BigIntPK = sa.BigInteger().with_variant(sa.Integer, "sqlite") revision = '0003' down_revision = '0002' branch_labels = None depends_on = None def upgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### op.create_table('publishers', sa.Column('id', sa.BigInteger().with_variant(sa.Integer(), 'sqlite'), autoincrement=True, nullable=False), sa.Column('tenant', sa.String(length=64), nullable=False), sa.Column('name', sa.String(length=128), nullable=False), sa.Column('token_hash', sa.String(length=64), nullable=False), sa.Column('description', sa.Text(), nullable=True), sa.Column('created_at', sa.DateTime(timezone=True), nullable=False), sa.Column('revoked_at', sa.DateTime(timezone=True), nullable=True), sa.PrimaryKeyConstraint('id'), sa.UniqueConstraint('tenant', 'name', name='uq_publisher_name'), sa.UniqueConstraint('token_hash', name='uq_publisher_token') ) op.add_column('index_entries', sa.Column('published_by', sa.String(length=128), nullable=True)) # ### end Alembic commands ### def downgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### op.drop_column('index_entries', 'published_by') op.drop_table('publishers') # ### end Alembic commands ###