Skip to content
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
f14178b
Add AWS credentials database tables for static and temporary credentials
Eden-D-Zhang Oct 20, 2025
08682e0
Initialize AWS credential tables in database setup script
Eden-D-Zhang Oct 20, 2025
5e0793e
Add Pydantic models for AWS credentials with validation and conversio…
Eden-D-Zhang Oct 20, 2025
a395256
Add S3CredentialManager class for database credential CRUD operations
Eden-D-Zhang Oct 20, 2025
535203c
Implement session token cache methods for temporary credential manage…
Eden-D-Zhang Oct 20, 2025
9cac4c3
Align credential name validation pattern in Pydantic model with manag…
Eden-D-Zhang Oct 20, 2025
3906383
Merge branch 'main' of https://github.com/Eden-D-Zhang/clp into packa…
Eden-D-Zhang Oct 20, 2025
febfb75
Use modern type syntax and improve code organization in credential ma…
Eden-D-Zhang Oct 20, 2025
5344d16
Merge branch 'main' of https://github.com/y-scope/clp into package-s3…
Eden-D-Zhang Oct 23, 2025
85ce7f9
Use clp logger
Eden-D-Zhang Oct 23, 2025
517c995
Remove unnecessary functions
Eden-D-Zhang Oct 23, 2025
b1f70d1
Lint
Eden-D-Zhang Oct 23, 2025
e7f8853
Remove unused import
Eden-D-Zhang Oct 23, 2025
99c1dbf
Remove unused import again
Eden-D-Zhang Oct 23, 2025
d3808b2
Coderabbit review
Eden-D-Zhang Oct 23, 2025
58f05e0
Lint
Eden-D-Zhang Oct 23, 2025
417d73e
Merge branch 'main' of https://github.com/y-scope/clp into package-s3…
Eden-D-Zhang Oct 27, 2025
2576b2e
Fix comment
Eden-D-Zhang Oct 27, 2025
2391c19
Clean up docstrings.
Eden-D-Zhang Oct 27, 2025
4fc9a89
Clean up docstrings.
Eden-D-Zhang Oct 27, 2025
2b3258a
Merge branch 'package-s3-credentials' of https://github.com/Eden-D-Zh…
Eden-D-Zhang Oct 27, 2025
36c9a65
Docstrings again
Eden-D-Zhang Oct 27, 2025
51c92fc
Fix index length
Eden-D-Zhang Oct 30, 2025
4be0a49
Add some descriptions
Eden-D-Zhang Nov 3, 2025
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
92 changes: 92 additions & 0 deletions components/clp-py-utils/clp_py_utils/clp_config.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
import pathlib
from datetime import datetime
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix tz-naive defaults and import; avoid import-time evaluation.

Use Field(default_factory=...) with UTC to prevent tz-naive values and import-time evaluation.

-from datetime import datetime
+from datetime import datetime, timezone
@@
-    created_at: datetime = datetime.now()
-    updated_at: datetime = datetime.now()
+    created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
+    updated_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))

Also applies to: 442-443

🤖 Prompt for AI Agents
In components/clp-py-utils/clp_py_utils/clp_config.py around line 3 (and also
lines 442-443), replace any direct datetime import/usages that create tz-naive
values at import time with a timezone-aware default_factory: import datetime and
timezone (from datetime import datetime, timezone) and update Field(default=...)
or module-level datetime.utcnow() calls to Field(default_factory=lambda:
datetime.now(timezone.utc)) so defaults are created at runtime and are
UTC-aware; ensure you import Field from pydantic (or the correct config
dataclass provider) if not already.

from enum import auto
from typing import Annotated, Any, ClassVar, Literal, Optional, Union

Expand All @@ -11,6 +12,7 @@
model_validator,
PlainSerializer,
PrivateAttr,
SecretStr,
)
from strenum import KebabCaseStrEnum, LowercaseStrEnum

Expand Down Expand Up @@ -413,6 +415,96 @@ def validate_authentication(cls, data):
return data


class AwsCredential(BaseModel):
"""
Represents a stored AWS credential retrieved from the database.

This model is used for credentials that are persisted in the aws_credentials table.
Credentials can be either static (access key + secret key) or configured for role
assumption (with role_arn set for Phase 2).
"""

id: int
name: Annotated[
str,
Field(
min_length=1,
max_length=255,
pattern=r"^[a-zA-Z0-9_-]+$",
description="Credential name (alphanumeric, hyphens, underscores only; 1-255 characters)",
),
]

access_key_id: SecretStr
secret_access_key: SecretStr
role_arn: str | None = None

created_at: datetime = datetime.now()
updated_at: datetime = datetime.now()

def to_s3_credentials(self) -> S3Credentials:
"""
Converts to S3Credentials for use with boto3.

Note: This only works for static credentials. For temporary credentials
with session tokens, use the TemporaryCredential model instead.

:return: S3Credentials object with secrets revealed.
"""
return S3Credentials(
access_key_id=self.access_key_id.get_secret_value(),
secret_access_key=self.secret_access_key.get_secret_value(),
session_token=None,
)


class TemporaryCredential(BaseModel):
"""
Represents cached temporary credentials (session tokens).

This model is used for credentials cached in the aws_temporary_credentials table.
These credentials can come from various sources:
- STS AssumeRole operations
- Resource-specific session tokens

The 'source' field tracks the origin of the session token, which can be:
- A role ARN: "arn:aws:iam::123456789012:role/MyRole"
- An S3 resource ARN: "arn:aws:s3:::bucket/path/*"
"""

id: int
long_term_key_id: int # Foreign key to aws_credentials table
access_key_id: SecretStr
secret_access_key: SecretStr
session_token: SecretStr
source: str # Role ARN or S3 resource ARN
expires_at: datetime
created_at: datetime

def to_s3_credentials(self) -> S3Credentials:
"""
Converts to S3Credentials for use with boto3.

:return: S3Credentials object with secrets revealed.
"""
return S3Credentials(
access_key_id=self.access_key_id.get_secret_value(),
secret_access_key=self.secret_access_key.get_secret_value(),
session_token=self.session_token.get_secret_value(),
)

def is_expired(self, buffer_minutes: int = 5) -> bool:
"""
Checks if credential is expired or expiring soon.

:param buffer_minutes: Minutes of buffer before expiration to consider credential expired.
:return: True if expired or expiring within buffer_minutes.
"""
from datetime import timedelta

return datetime.now() >= self.expires_at - timedelta(minutes=buffer_minutes)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Make is_expired time-safe (UTC, tz-aware).

Comparing tz-naive datetimes risks errors and drift across hosts. Normalise to UTC and handle naive DB values.

-    def is_expired(self, buffer_minutes: int = 5) -> bool:
+    def is_expired(self, buffer_minutes: int = 5) -> bool:
         """
         Checks if credential is expired or expiring soon.
@@
-        from datetime import timedelta
-
-        return datetime.now() >= self.expires_at - timedelta(minutes=buffer_minutes)
+        from datetime import timedelta, timezone
+        now = datetime.now(timezone.utc)
+        exp = self.expires_at
+        if exp.tzinfo is None:
+            # Assume DB stores UTC; attach UTC tzinfo to compare safely.
+            exp = exp.replace(tzinfo=timezone.utc)
+        return now >= exp - timedelta(minutes=buffer_minutes)

If DB values are not UTC, document and convert at read time.


I'll verify this review comment by examining the codebase to understand the current implementation and the timezone handling.


🏁 Script executed:

#!/bin/bash
# Find and examine the class definition containing is_expired
fd -e py . | xargs rg -n "def is_expired|expires_at" --context=5 components/clp-py-utils/clp_py_utils/clp_config.py

Length of output: 17989


🏁 Script executed:

#!/bin/bash
# Look at the full class structure around line 496
fd clp_config.py | xargs cat | head -550 | tail -100

Length of output: 3120


🏁 Script executed:

#!/bin/bash
# Search for expires_at field definition and initialization
fd -e py . | xargs rg -n "expires_at\s*=" --context=3 | head -40

Length of output: 740


🏁 Script executed:

#!/bin/bash
# Check timezone imports and UTC usage patterns in the file
fd clp_config.py | xargs rg -n "import.*timezone|from.*timezone|timezone\.utc|datetime\.now" 

Length of output: 180


🏁 Script executed:

#!/bin/bash
# Search for other datetime comparisons that might have similar issues
fd -e py . | xargs rg -n "datetime\.now\(\)" --context=2 | head -30

Length of output: 3344


🏁 Script executed:

#!/bin/bash
# Check if there are DB interactions or datetime conversions
fd -e py . | xargs rg -n "tzinfo|utc|UTC" components/clp-py-utils/clp_py_utils/ | head -20

Length of output: 1970


🏁 Script executed:

#!/bin/bash
# Look for any tests or usages of is_expired method
fd -e py . | xargs rg -n "is_expired" | head -20

Length of output: 751


🏁 Script executed:

#!/bin/bash
# Examine the class structure and field definitions
fd clp_config.py | xargs ast-grep --pattern $'class $_ {
  $$$
  expires_at
  $$$
}'

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Get the broader context around the is_expired method
fd clp_config.py | xargs python3 << 'EOF'
with open('components/clp-py-utils/clp_py_utils/clp_config.py', 'r') as f:
    lines = f.readlines()
    # Look for is_expired and surrounding context
    for i, line in enumerate(lines):
        if 'is_expired' in line or 'expires_at' in line:
            start = max(0, i - 10)
            end = min(len(lines), i + 15)
            print(f"Lines {start+1}-{end}:")
            for j in range(start, end):
                print(f"{j+1:4d}: {lines[j]}", end='')
            print("\n" + "="*80 + "\n")
EOF

Length of output: 87


🏁 Script executed:

#!/bin/bash
# Check the imports at the top of the file
fd clp_config.py | xargs head -30

Length of output: 667


🏁 Script executed:

#!/bin/bash
# Look at how datetime is imported and used
fd clp_config.py | xargs rg -n "^from datetime|^import datetime" -A 5

Length of output: 172


🏁 Script executed:

#!/bin/bash
# Check type hints for expires_at
fd clp_config.py | xargs rg -n "expires_at.*:" --context=2

Length of output: 146


🏁 Script executed:

#!/bin/bash
# Search for DB schema or ORM model definitions
fd -e py . | xargs rg -n "expires_at" --context=4 components/

Length of output: 22398


🏁 Script executed:

#!/bin/bash
# Check if datetime.now() returns naive or if tzinfo handling exists
fd clp_config.py | xargs python3 << 'EOF'
import re
with open('components/clp-py-utils/clp_py_utils/clp_config.py', 'r') as f:
    content = f.read()
    # Find the class and is_expired method
    if 'def is_expired' in content:
        idx = content.find('def is_expired')
        print("is_expired method found at character index:", idx)
        print("\nContext (500 chars before and after):")
        print(content[max(0, idx-500):idx+500])
        print("\n" + "="*80)
    # Check for timezone usage
    if 'timezone' in content:
        print("timezone import/usage detected")
    if 'utc' in content.lower():
        print("UTC references detected")
EOF

Length of output: 89



🏁 Script executed:

#!/bin/bash
# Search for usage of is_expired method on TemporaryCredential
fd -e py . | xargs rg -n "\.is_expired\(" --context=3 | grep -A3 -B3 "TemporaryCredential\|temporary_credential\|session_token"

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for where TemporaryCredential is instantiated and expires_at is set
fd -e py . | xargs rg -n "TemporaryCredential\(" --context=2

Length of output: 874


🏁 Script executed:

#!/bin/bash
# Check AWS credential manager to see how it populates expires_at
fd s3_credential_manager.py | xargs rg -n "cache_session_token\|expires_at" --context=3 | head -50

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for datetime defaults or initialization in TemporaryCredential
fd clp_config.py | xargs rg -n "created_at\|now\(" --context=2

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check if MySQL connection has timezone configuration
fd -e py . | xargs rg -n "autocommit=True\|timezone\|convert_tz" components/clp-py-utils/clp_py_utils/

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check imports in s3_credential_manager to see how datetimes are handled
fd s3_credential_manager.py | xargs head -50

Length of output: 1437


🏁 Script executed:

#!/bin/bash
# Look at actual usage: where is_expired is called
fd -e py . | xargs rg -B5 -A5 "\.is_expired\(" 

Length of output: 3668



🏁 Script executed:

#!/bin/bash
# Comprehensive search: is_expired called anywhere on temporary_credential or TemporaryCredential
fd -e py . | xargs rg -n "temporary_credential|temp_cred" --context=2 | head -30

Length of output: 2786


🏁 Script executed:

#!/bin/bash
# Check if is_expired might be called indirectly or through method chaining
fd -e py . | xargs rg -n "get_cached_session_token|TemporaryCredential" --context=3 | grep -A10 "\.is_expired\|check.*expir"

Length of output: 0


Implement timezone-safe expiration check using UTC.

The current is_expired() method compares naive datetimes, which risks errors across hosts in different timezones. While the method is not currently called in the codebase, it should follow the established pattern used elsewhere (e.g., session_manager.py lines 72, 150) to ensure correctness if invoked. Apply the suggested fix to handle naive database values and use datetime.now(timezone.utc) for safe comparison.

    def is_expired(self, buffer_minutes: int = 5) -> bool:
        """
        Checks if credential is expired or expiring soon.

        :param buffer_minutes: Minutes of buffer before expiration to consider credential expired.
        :return: True if expired or expiring within buffer_minutes.
        """
-        from datetime import timedelta
-
-        return datetime.now() >= self.expires_at - timedelta(minutes=buffer_minutes)
+        from datetime import timedelta, timezone
+        now = datetime.now(timezone.utc)
+        exp = self.expires_at
+        if exp.tzinfo is None:
+            # Assume DB stores UTC; attach UTC tzinfo to compare safely.
+            exp = exp.replace(tzinfo=timezone.utc)
+        return now >= exp - timedelta(minutes=buffer_minutes)
🧰 Tools
🪛 Ruff (0.14.1)

505-505: datetime.datetime.now() called without a tz argument

(DTZ005)

🤖 Prompt for AI Agents
In components/clp-py-utils/clp_py_utils/clp_config.py around lines 496 to 505,
the is_expired method compares naive datetimes; update it to be timezone-safe by
using datetime.now(timezone.utc) and ensuring self.expires_at is timezone-aware
(if naive, treat it as UTC via replace(tzinfo=timezone.utc) or use an aware
conversion pattern like in session_manager.py lines 72/150) before subtracting
timedelta(buffer_minutes); perform the comparison with both values in UTC to
avoid cross-host timezone issues.



class S3Config(BaseModel):
region_code: NonEmptyStr
bucket: NonEmptyStr
Expand Down
82 changes: 82 additions & 0 deletions components/clp-py-utils/clp_py_utils/clp_metadata_db_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

ARCHIVE_TAGS_TABLE_SUFFIX = "archive_tags"
ARCHIVES_TABLE_SUFFIX = "archives"
AWS_CREDENTIALS_TABLE_SUFFIX = "aws_credentials"
AWS_TEMPORARY_CREDENTIALS_TABLE_SUFFIX = "aws_temporary_credentials"
COLUMN_METADATA_TABLE_SUFFIX = "column_metadata"
DATASETS_TABLE_SUFFIX = "datasets"
FILES_TABLE_SUFFIX = "files"
Expand All @@ -21,6 +23,8 @@
TABLE_SUFFIX_MAX_LEN = max(
len(ARCHIVE_TAGS_TABLE_SUFFIX),
len(ARCHIVES_TABLE_SUFFIX),
len(AWS_CREDENTIALS_TABLE_SUFFIX),
len(AWS_TEMPORARY_CREDENTIALS_TABLE_SUFFIX),
len(COLUMN_METADATA_TABLE_SUFFIX),
len(DATASETS_TABLE_SUFFIX),
len(FILES_TABLE_SUFFIX),
Expand Down Expand Up @@ -110,6 +114,48 @@ def _create_column_metadata_table(db_cursor, table_prefix: str, dataset: str) ->
)


def _create_aws_credentials_table(db_cursor, aws_credentials_table_name: str) -> None:
db_cursor.execute(
f"""
CREATE TABLE IF NOT EXISTS `{aws_credentials_table_name}` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL UNIQUE,
`access_key_id` VARCHAR(255) NOT NULL,
`secret_access_key` VARCHAR(255) NOT NULL,
`role_arn` VARCHAR(2048),
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `name_unique` (`name`)
) ROW_FORMAT=DYNAMIC
"""
)
Comment on lines 117 to 131
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Remove redundant unique definition on name.

You have both UNIQUE at column level and an explicit UNIQUE KEY. Keep one to avoid duplicate unique indexes and overhead.

         CREATE TABLE IF NOT EXISTS `{aws_credentials_table_name}` (
             `id` INT NOT NULL AUTO_INCREMENT,
-            `name` VARCHAR(255) NOT NULL UNIQUE,
+            `name` VARCHAR(255) NOT NULL UNIQUE,
             `access_key_id` VARCHAR(255) NOT NULL,
             `secret_access_key` VARCHAR(255) NOT NULL,
             `role_arn` VARCHAR(2048),
             `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
             `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
             PRIMARY KEY (`id`),
-            UNIQUE KEY `name_unique` (`name`)
         ) ROW_FORMAT=DYNAMIC
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def _create_aws_credentials_table(db_cursor, aws_credentials_table_name: str) -> None:
db_cursor.execute(
f"""
CREATE TABLE IF NOT EXISTS `{aws_credentials_table_name}` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL UNIQUE,
`access_key_id` VARCHAR(255) NOT NULL,
`secret_access_key` VARCHAR(255) NOT NULL,
`role_arn` VARCHAR(2048),
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `name_unique` (`name`)
) ROW_FORMAT=DYNAMIC
"""
)
def _create_aws_credentials_table(db_cursor, aws_credentials_table_name: str) -> None:
db_cursor.execute(
f"""
CREATE TABLE IF NOT EXISTS `{aws_credentials_table_name}` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(255) NOT NULL UNIQUE,
`access_key_id` VARCHAR(255) NOT NULL,
`secret_access_key` VARCHAR(255) NOT NULL,
`role_arn` VARCHAR(2048),
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ROW_FORMAT=DYNAMIC
"""
)
🤖 Prompt for AI Agents
In components/clp-py-utils/clp_py_utils/clp_metadata_db_utils.py around lines
117 to 132, the CREATE TABLE defines `name` as VARCHAR(255) NOT NULL UNIQUE and
also adds a separate UNIQUE KEY `name_unique`, creating redundant unique
indexes; remove one of the duplicate constraints — either drop the column-level
UNIQUE from `name` or delete the explicit UNIQUE KEY `name_unique` line — so
only a single unique constraint remains, then run migrations/DDL to apply the
updated table definition.



def _create_aws_temporary_credentials_table(
db_cursor, aws_temporary_credentials_table_name: str, aws_credentials_table_name: str
) -> None:
db_cursor.execute(
f"""
CREATE TABLE IF NOT EXISTS `{aws_temporary_credentials_table_name}` (
`id` INT NOT NULL AUTO_INCREMENT,
`long_term_key_id` INT NOT NULL,
`access_key_id` VARCHAR(255) NOT NULL,
`secret_access_key` VARCHAR(255) NOT NULL,
`session_token` VARCHAR(512) NOT NULL,
`source` VARCHAR(2048) NOT NULL,
`expires_at` DATETIME NOT NULL,
`created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `long_term_key_expires` (`long_term_key_id`, `expires_at`),
KEY `source_expires` (`source`, `expires_at`),
FOREIGN KEY (`long_term_key_id`) REFERENCES `{aws_credentials_table_name}` (`id`)
ON DELETE CASCADE
) ROW_FORMAT=DYNAMIC
"""
)


def _get_table_name(prefix: str, suffix: str, dataset: str | None) -> str:
"""
:param prefix:
Expand Down Expand Up @@ -145,6 +191,34 @@ def create_datasets_table(db_cursor, table_prefix: str) -> None:
)


def create_aws_credentials_table(db_cursor, table_prefix: str) -> None:
"""
Creates the AWS credentials table for storing user-managed static credentials.

:param db_cursor: The database cursor to execute the table creation.
:param table_prefix: A string to prepend to the table name.
"""
aws_credentials_table_name = get_aws_credentials_table_name(table_prefix)
_create_aws_credentials_table(db_cursor, aws_credentials_table_name)


def create_aws_temporary_credentials_table(db_cursor, table_prefix: str) -> None:
"""
Creates the AWS temporary credentials table for storing cached session tokens.

This table caches session tokens from various sources (user-provided, role assumption, etc.)
to enable efficient credential reuse. It references the aws_credentials table via foreign key.

:param db_cursor: The database cursor to execute the table creation.
:param table_prefix: A string to prepend to the table name.
"""
aws_credentials_table_name = get_aws_credentials_table_name(table_prefix)
aws_temporary_credentials_table_name = get_aws_temporary_credentials_table_name(table_prefix)
_create_aws_temporary_credentials_table(
db_cursor, aws_temporary_credentials_table_name, aws_credentials_table_name
)


def add_dataset(
db_conn,
db_cursor,
Expand Down Expand Up @@ -300,6 +374,14 @@ def get_archives_table_name(table_prefix: str, dataset: str | None) -> str:
return _get_table_name(table_prefix, ARCHIVES_TABLE_SUFFIX, dataset)


def get_aws_credentials_table_name(table_prefix: str) -> str:
return _get_table_name(table_prefix, AWS_CREDENTIALS_TABLE_SUFFIX, None)


def get_aws_temporary_credentials_table_name(table_prefix: str) -> str:
return _get_table_name(table_prefix, AWS_TEMPORARY_CREDENTIALS_TABLE_SUFFIX, None)


def get_column_metadata_table_name(table_prefix: str, dataset: str | None) -> str:
return _get_table_name(table_prefix, COLUMN_METADATA_TABLE_SUFFIX, dataset)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
StorageEngine,
)
from clp_py_utils.clp_metadata_db_utils import (
create_aws_credentials_table,
create_aws_temporary_credentials_table,
create_datasets_table,
create_metadata_db_tables,
)
Expand Down Expand Up @@ -61,6 +63,9 @@ def main(argv):
with closing(sql_adapter.create_connection(True)) as metadata_db, closing(
metadata_db.cursor(dictionary=True)
) as metadata_db_cursor:
create_aws_credentials_table(metadata_db_cursor, table_prefix)
create_aws_temporary_credentials_table(metadata_db_cursor, table_prefix)

if StorageEngine.CLP_S == storage_engine:
create_datasets_table(metadata_db_cursor, table_prefix)
else:
Expand Down
Loading
Loading