Skip to content

UN-3343 [FEAT] Support AWS S3 connector authentication via IRSA#1866

Open
kirtimanmishrazipstack wants to merge 8 commits intomainfrom
UN-3343-Support-AWS-S3-connector-IAM
Open

UN-3343 [FEAT] Support AWS S3 connector authentication via IRSA#1866
kirtimanmishrazipstack wants to merge 8 commits intomainfrom
UN-3343-Support-AWS-S3-connector-IAM

Conversation

@kirtimanmishrazipstack
Copy link
Contributor

@kirtimanmishrazipstack kirtimanmishrazipstack commented Mar 18, 2026

What

  • Allow the MinIO/S3 connector to authenticate via IAM roles (IRSA / instance profile) when static credentials (key & secret) are left blank.

Why

  • Users running Unstract on AWS (EKS with IRSA, EC2 with instance profiles) should not need to provide static access keys. Boto3's default credential chain should be leveraged automatically when no explicit credentials are configured.

How

  • minio.py: MinioFS.__init__ now strips and normalises key, secret, and endpoint_url. Only passes them to S3FileSystem when non-empty, letting boto3's default credential chain take over otherwise. Tracks a _using_static_creds flag for error messaging. Logging switched to lazy % formatting.
  • exceptions.py: Splits the single S3FS_EXC_TO_UNSTRACT_EXC dict into three maps — _STATIC (key/secret errors), _AMBIENT (IRSA/IAM errors), _COMMON (shared errors like port/bucket). handle_s3fs_exception gains a using_static_creds param to select the right error map.
  • json_schema.json: key and secret removed from required array (now optional). Field descriptions updated to mention "leave blank to use IAM role / instance profile". endpoint_url description simplified.

Can this PR break any existing features. If yes, please list possible items. If no, please explain why. (PS: Admins do not merge the PR without this section filled)

  • No. Existing users who provide static credentials will see no behavior change — credentials are passed through to S3FileSystem exactly as before. The new IAM path only activates when credentials are explicitly left blank.

Database Migrations

  • None

Env Config

  • None

Relevant Docs

Related Issues or PRs

Dependencies Versions

  • No new dependencies

Notes on Testing

  • Tested a s3 connector with blank credentials on an IRSA-enabled EKS pod — boto3 picks up the IAM role automatically.
  • ETL run successfully for that connector

Screenshots

  • Showing screenshot of successful s3 connection + ETL
9 8 7
  • N/A

Checklist

I have read and understood the Contribution Guidelines.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 18, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds explicit typing and expands the S3/MinIO exception substring→message mapping; no control-flow change in exception handling. MinioFS now sanitizes credential inputs, builds a creds dict only from non-empty values and passes it via **creds to S3FileSystem; logging was converted to parameterized form. JSON schema no longer requires key/secret and clarifies descriptions.

Changes

Cohort / File(s) Summary
Exception mapping
unstract/connectors/src/unstract/connectors/filesystems/minio/exceptions.py
Added explicit type annotation S3FS_EXC_TO_UNSTRACT_EXC: dict[str, str] and expanded substring keys to cover additional auth, permission, bucket, connectivity, and clock-skew messages. handle_s3fs_exception retains its existing first-match behavior and still appends the matched friendly message or original exception text into ConnectorError.
Credential handling & logging
unstract/connectors/src/unstract/connectors/filesystems/minio/minio.py
Sanitizes credential values with (value or "").strip(), builds a creds dict only including non-empty entries (key+secret together; endpoint_url if provided), passes credentials via **creds to S3FileSystem, and replaces f-string logs with parameterized logging. Minor typing added for file_hash and logging call sites updated.
Schema updates
unstract/connectors/src/unstract/connectors/filesystems/minio/static/json_schema.json
Removed key and secret from required. Updated property descriptions: key and secret note they can be left blank to use IAM role/instance profile, endpoint_url clarified as optional (default AWS S3), and region_name clarified for AWS vs Minio usage.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The PR description is comprehensive and well-structured, covering all required template sections including What, Why, How, breaking changes analysis, testing notes, and screenshots demonstrating successful IRSA authentication.
Docstring Coverage ✅ Passed Docstring coverage is 87.50% which is sufficient. The required threshold is 80.00%.
Title check ✅ Passed The title clearly and specifically describes the main feature: adding support for AWS S3 connector authentication via IRSA, which aligns with the changeset's core objective.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch UN-3343-Support-AWS-S3-connector-IAM
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 18, 2026

Greptile Summary

This PR enables the MinIO/S3 connector to authenticate via IAM roles (IRSA, EC2 instance profiles) when static credentials are left blank, by conditionally passing key/secret/endpoint_url to S3FileSystem only when non-empty and letting boto3's default credential chain take over otherwise. The exceptions.py mapping is also expanded with new OIDC, IAM, network, and clock-skew error keys.

  • minio.py: Credential normalisation is clean and backward-compatible; static-credential users are completely unaffected. Lazy-% log formatting is a welcome improvement.
  • exceptions.py: The unified single-dict approach works, though two issues remain — the InvalidIdentityToken message uses Kubernetes-specific "ServiceAccount" language that misleads GitHub Actions / GitLab CI OIDC users, and s3:DeleteObject is absent from the AccessDenied guidance despite the connector supporting writes and deletes.
  • json_schema.json: key and secret correctly removed from required; secret is still missing "default": "" for consistency with key.
  • The PR description refers to a three-dict design (_STATIC / _AMBIENT / _COMMON) and a using_static_creds parameter on handle_s3fs_exception that were not implemented in the final code — the description should be updated to reflect the simpler unified-dict approach that was actually shipped.

Confidence Score: 3/5

  • Safe for existing static-credential users, but the unified error-map has two gaps (misleading OIDC message, missing s3:DeleteObject in permission guidance) that should be fixed before merging.
  • The core credential-selection logic in minio.py is correct and backward-compatible. The risk is concentrated in exceptions.py: the InvalidIdentityToken message will send non-EKS OIDC users chasing Kubernetes ServiceAccounts, and the omission of s3:DeleteObject from the AccessDenied guidance will leave write-enabled users confused after a partial permission grant. Neither is a runtime failure, but both produce actively misleading UX for the IAM flows this PR is intended to support.
  • exceptions.py — review the InvalidIdentityToken message wording and add s3:DeleteObject to the AccessDenied guidance.

Important Files Changed

Filename Overview
unstract/connectors/src/unstract/connectors/filesystems/minio/exceptions.py Unified error-mapping dict expanded with new IAM/OIDC/network error keys; InvalidIdentityToken message contains Kubernetes-specific "ServiceAccount" language that misleads non-EKS OIDC users, and s3:DeleteObject is missing from the AccessDenied permission guidance despite can_write() being true.
unstract/connectors/src/unstract/connectors/filesystems/minio/minio.py Credential normalization logic is clean — only forwards key/secret/endpoint to S3FileSystem when non-empty, letting boto3's credential chain handle IRSA. Logging correctly switched to lazy-% format. Existing users with static credentials are unaffected.
unstract/connectors/src/unstract/connectors/filesystems/minio/static/json_schema.json Correctly removes key and secret from required; endpoint_url intentionally kept required with its pre-existing default. secret field is still missing a "default": "" entry for consistency with key.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[MinioFS.__init__ called] --> B{key AND secret\nboth non-empty?}
    B -- Yes --> C[creds = key + secret]
    B -- No --> D[creds = empty\nboto3 credential chain]
    C --> E{endpoint_url\nnon-empty?}
    D --> E
    E -- Yes --> F[creds += endpoint_url]
    E -- No --> G[S3FileSystem\nno endpoint_url]
    F --> H[S3FileSystem\nwith explicit creds + endpoint]
    G --> I[boto3 resolves\nendpoint automatically]
    H --> J[test_credentials calls ls]
    I --> J
    J -- Success --> K[return True]
    J -- Exception --> L[handle_s3fs_exception]
    L --> M{substring match\nin S3FS_EXC_TO_UNSTRACT_EXC?}
    M -- Match --> N[User-friendly ConnectorError]
    M -- No match --> O[Raw exception string\nin ConnectorError]
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: unstract/connectors/src/unstract/connectors/filesystems/minio/exceptions.py
Line: 19-22

Comment:
**Kubernetes-specific guidance in a general OIDC error**

The `InvalidIdentityToken` message references "ServiceAccount configuration", but `InvalidIdentityToken` is raised by any OIDC-based web identity federation — including GitHub Actions OIDC, GitLab CI OIDC, and on-premise OIDC providers. "ServiceAccount" is a Kubernetes-only concept, so this guidance is actively misleading for non-EKS OIDC callers.

Consider making the message provider-agnostic:

```suggestion
    "InvalidIdentityToken": (
        "The identity token provided is invalid. Verify the OIDC provider "
        "configuration and ensure the token audience/issuer matches the IAM "
        "role's trust policy."
    ),
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: unstract/connectors/src/unstract/connectors/filesystems/minio/exceptions.py
Line: 28-33

Comment:
**`s3:DeleteObject` omitted from `AccessDenied` permission guidance**

`can_write()` returns `True` and the connector supports file deletion. The `AccessDenied` message lists `s3:ListAllMyBuckets, s3:ListBucket, s3:GetObject, s3:PutObject` but silently drops `s3:DeleteObject`. A user whose role is missing only `s3:DeleteObject` will follow this guidance exactly, grant every listed permission, and still receive `AccessDenied` when deleting files — with no clue as to why.

```suggestion
    "AccessDenied": (
        "Access denied. The IAM user or role does not have sufficient S3 "
        "permissions. Ensure the policy grants the required S3 actions "
        "(s3:ListAllMyBuckets, s3:ListBucket, s3:GetObject, s3:PutObject, "
        "s3:DeleteObject) on the target bucket."
    ),
```

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: "PR comments"

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
unstract/connectors/src/unstract/connectors/filesystems/minio/static/json_schema.json (1)

5-9: ⚠️ Potential issue | 🟡 Minor

Inconsistency: endpoint_url is required but description says "leave blank".

The endpoint_url field is listed in the required array (line 7) but its description says "leave blank for default AWS S3" (line 32). This is contradictory. Additionally, it has a non-empty default value (https://s3.amazonaws.com), so users technically cannot leave it blank.

Consider either:

  1. Removing endpoint_url from the required array if blank values should be allowed, or
  2. Updating the description to clarify that the default value is used for AWS S3.
📝 Suggested description fix (if keeping required)
     "endpoint_url": {
       "type": "string",
       "title": "Endpoint URL",
       "default": "https://s3.amazonaws.com",
-      "description": "Endpoint URL (leave blank for default AWS S3)"
+      "description": "Endpoint URL (use default for AWS S3, or provide custom URL for MinIO/S3-compatible storage)"
     },

Also applies to: 28-32

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@unstract/connectors/src/unstract/connectors/filesystems/minio/static/json_schema.json`
around lines 5 - 9, The JSON schema currently lists "endpoint_url" in the
"required" array while its description tells users to "leave blank for default
AWS S3" and it has a non-empty default; fix by either (A) removing
"endpoint_url" from the "required" array so blank/omitted values are allowed, or
(B) keep it required but update the "endpoint_url" description and default to
clearly state that the default "https://s3.amazonaws.com" will be used for AWS
S3 (and remove the "leave blank" wording); locate the "required" array and the
"endpoint_url" property in the schema to apply the chosen change (modify the
"required" array or the "endpoint_url" property's "description" and/or
"default").
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@unstract/connectors/src/unstract/connectors/filesystems/minio/minio.py`:
- Around line 19-33: The code in minio.py currently treats partial credentials
(only key or only secret) as absent and silently falls back to IAM; update the
validation around key/secret (the variables key, secret, creds and the
assignment to self._using_static_creds) to detect the case where exactly one of
key or secret is provided and either raise a ConnectorError with a clear message
or emit a warning that static credentials are incomplete and IAM will be used;
if you choose to raise, import ConnectorError from
unstract.connectors.exceptions and raise it before building creds, otherwise
call the module logger to warn and ensure self._using_static_creds remains
False.

In
`@unstract/connectors/src/unstract/connectors/filesystems/minio/static/json_schema.json`:
- Around line 34-39: The JSON schema's "region_name" property has an invalid
default "ap-south"; update the default to a valid AWS region identifier (e.g.,
"ap-south-1") or set the default to null/"" to force explicit configuration;
modify the "region_name" object's "default" value in json_schema.json
accordingly so it uses a correct region code or an empty value.

---

Outside diff comments:
In
`@unstract/connectors/src/unstract/connectors/filesystems/minio/static/json_schema.json`:
- Around line 5-9: The JSON schema currently lists "endpoint_url" in the
"required" array while its description tells users to "leave blank for default
AWS S3" and it has a non-empty default; fix by either (A) removing
"endpoint_url" from the "required" array so blank/omitted values are allowed, or
(B) keep it required but update the "endpoint_url" description and default to
clearly state that the default "https://s3.amazonaws.com" will be used for AWS
S3 (and remove the "leave blank" wording); locate the "required" array and the
"endpoint_url" property in the schema to apply the chosen change (modify the
"required" array or the "endpoint_url" property's "description" and/or
"default").

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ef8d51b7-40d9-48d6-b173-e8cd2c792231

📥 Commits

Reviewing files that changed from the base of the PR and between 41137d8 and 3c64f0a.

📒 Files selected for processing (3)
  • unstract/connectors/src/unstract/connectors/filesystems/minio/exceptions.py
  • unstract/connectors/src/unstract/connectors/filesystems/minio/minio.py
  • unstract/connectors/src/unstract/connectors/filesystems/minio/static/json_schema.json

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@unstract/connectors/src/unstract/connectors/filesystems/minio/exceptions.py`:
- Around line 30-35: The shared AccessDenied message (_ACCESS_DENIED_MSG) is
AWS-specific (mentions IAM and s3:* actions) but is used in the common mapping
S3FS_EXC_TO_UNSTRACT_EXC_COMMON and thus can mislead non-AWS backends like
MinIO; change the string to be backend-agnostic and actionable (e.g., advise
checking bucket permissions, credentials, and access policies for the storage
backend or service) and remove the hardcoded AWS IAM action names so callers
using MinIO or other S3-compatible systems receive correct, generic permission
guidance.
- Around line 12-15: The ambient-auth fallback message in _AMBIENT_AUTH_MSG is
too IRSA-specific; update its text to reference the full boto3/default
credential chain (environment variables, shared credentials/profile, IAM role,
IRSA/service account, etc.) so guidance covers bad env/profile credentials as
well; make the same wording change for the other ambient-auth message variant
around lines 38-40 (the other AWS auth fallback constant) so both constants
consistently mention environment variables, shared credentials/profiles, IAM
roles and IRSA.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: cf6be913-3dea-4ea9-a6a0-a258ebfa37e3

📥 Commits

Reviewing files that changed from the base of the PR and between 4863d27 and 85c4ab5.

📒 Files selected for processing (1)
  • unstract/connectors/src/unstract/connectors/filesystems/minio/exceptions.py

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (2)
unstract/connectors/src/unstract/connectors/filesystems/minio/exceptions.py (2)

20-23: ⚠️ Potential issue | 🟡 Minor

Broaden ambient-auth guidance beyond IRSA-only hints.

Line 20 currently points users mainly to IAM role/IRSA, but ambient mode can also fail due to env/shared-profile credentials in the default AWS chain.

Suggested wording update
 _AMBIENT_AUTH_MSG = (
-    "AWS authentication failed — verify IAM role permissions "
-    "or IRSA service account annotation."
+    "AWS authentication failed — verify the active credential source in the "
+    "default AWS credential chain (environment variables, shared credentials/profile, "
+    "instance/task role, or IRSA service account annotation)."
 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@unstract/connectors/src/unstract/connectors/filesystems/minio/exceptions.py`
around lines 20 - 23, Update the _AMBIENT_AUTH_MSG constant to broaden
ambient-auth troubleshooting beyond IRSA by mentioning other credential sources
in the default AWS credential chain (environment variables, shared
credentials/profile, and EC2/ECS instance roles) so users know to check env vars
and shared AWS profiles as well as IAM/IRSA; modify the string value of
_AMBIENT_AUTH_MSG in exceptions.py to include these additional hints while
preserving the existing IAM/IRSA guidance.

38-43: ⚠️ Potential issue | 🟠 Major

Keep shared AccessDenied guidance backend-agnostic.

Line 38 is used for both S3 and MinIO (Line 74), but the current message is AWS IAM-action specific and can misdirect MinIO users.

Suggested backend-agnostic message
 _ACCESS_DENIED_MSG = (
-    "Access denied — the IAM user or role does not have sufficient S3 "
-    "permissions. Ensure the policy grants s3:ListAllMyBuckets (for connection "
-    "test), s3:GetObject, s3:PutObject, s3:ListBucket, and s3:DeleteObject on "
-    "the target bucket."
+    "Access denied — the configured credentials do not have sufficient "
+    "permissions for the target bucket. Verify the attached S3/MinIO policy "
+    "allows the operations required by this connector."
 )

Also applies to: 74-77

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@unstract/connectors/src/unstract/connectors/filesystems/minio/exceptions.py`
around lines 38 - 43, The current _ACCESS_DENIED_MSG is AWS IAM-specific and can
confuse MinIO users; update the _ACCESS_DENIED_MSG (and any duplicate at the
MinIO-specific message) to a backend-agnostic string that removes AWS IAM action
names and instead states that the client lacks required S3-compatible
permissions (e.g., needs list, get, put, and delete access on the target bucket
and list permission for connection tests), and ensure both uses reference this
single generic message variable (replace the MinIO-specific copy with the shared
_ACCESS_DENIED_MSG).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@unstract/connectors/src/unstract/connectors/filesystems/minio/exceptions.py`:
- Around line 20-23: Update the _AMBIENT_AUTH_MSG constant to broaden
ambient-auth troubleshooting beyond IRSA by mentioning other credential sources
in the default AWS credential chain (environment variables, shared
credentials/profile, and EC2/ECS instance roles) so users know to check env vars
and shared AWS profiles as well as IAM/IRSA; modify the string value of
_AMBIENT_AUTH_MSG in exceptions.py to include these additional hints while
preserving the existing IAM/IRSA guidance.
- Around line 38-43: The current _ACCESS_DENIED_MSG is AWS IAM-specific and can
confuse MinIO users; update the _ACCESS_DENIED_MSG (and any duplicate at the
MinIO-specific message) to a backend-agnostic string that removes AWS IAM action
names and instead states that the client lacks required S3-compatible
permissions (e.g., needs list, get, put, and delete access on the target bucket
and list permission for connection tests), and ensure both uses reference this
single generic message variable (replace the MinIO-specific copy with the shared
_ACCESS_DENIED_MSG).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f7055e6c-8213-44ff-bbec-afe42832c261

📥 Commits

Reviewing files that changed from the base of the PR and between 85c4ab5 and d930daa.

📒 Files selected for processing (1)
  • unstract/connectors/src/unstract/connectors/filesystems/minio/exceptions.py

@github-actions
Copy link
Contributor

Test Results

Summary
  • Runner Tests: 11 passed, 0 failed (11 total)
  • SDK1 Tests: 63 passed, 0 failed (63 total)

Runner Tests - Full Report
filepath function $$\textcolor{#23d18b}{\tt{passed}}$$ SUBTOTAL
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_logs}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_cleanup}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_cleanup\_skip}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_client\_init}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_get\_image\_exists}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_get\_image}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_get\_container\_run\_config}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_get\_container\_run\_config\_without\_mount}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_run\_container}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_get\_image\_for\_sidecar}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{runner/src/unstract/runner/clients/test\_docker.py}}$$ $$\textcolor{#23d18b}{\tt{test\_sidecar\_container}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{TOTAL}}$$ $$\textcolor{#23d18b}{\tt{11}}$$ $$\textcolor{#23d18b}{\tt{11}}$$
SDK1 Tests - Full Report
filepath function $$\textcolor{#23d18b}{\tt{passed}}$$ SUBTOTAL
$$\textcolor{#23d18b}{\tt{tests/test\_platform.py}}$$ $$\textcolor{#23d18b}{\tt{TestPlatformHelperRetry.test\_success\_on\_first\_attempt}}$$ $$\textcolor{#23d18b}{\tt{2}}$$ $$\textcolor{#23d18b}{\tt{2}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_platform.py}}$$ $$\textcolor{#23d18b}{\tt{TestPlatformHelperRetry.test\_retry\_on\_connection\_error}}$$ $$\textcolor{#23d18b}{\tt{2}}$$ $$\textcolor{#23d18b}{\tt{2}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_platform.py}}$$ $$\textcolor{#23d18b}{\tt{TestPlatformHelperRetry.test\_non\_retryable\_http\_error}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_platform.py}}$$ $$\textcolor{#23d18b}{\tt{TestPlatformHelperRetry.test\_retryable\_http\_errors}}$$ $$\textcolor{#23d18b}{\tt{3}}$$ $$\textcolor{#23d18b}{\tt{3}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_platform.py}}$$ $$\textcolor{#23d18b}{\tt{TestPlatformHelperRetry.test\_post\_method\_retry}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_platform.py}}$$ $$\textcolor{#23d18b}{\tt{TestPlatformHelperRetry.test\_retry\_logging}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_prompt.py}}$$ $$\textcolor{#23d18b}{\tt{TestPromptToolRetry.test\_success\_on\_first\_attempt}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_prompt.py}}$$ $$\textcolor{#23d18b}{\tt{TestPromptToolRetry.test\_retry\_on\_errors}}$$ $$\textcolor{#23d18b}{\tt{2}}$$ $$\textcolor{#23d18b}{\tt{2}}$$
$$\textcolor{#23d18b}{\tt{tests/test\_prompt.py}}$$ $$\textcolor{#23d18b}{\tt{TestPromptToolRetry.test\_wrapper\_methods\_retry}}$$ $$\textcolor{#23d18b}{\tt{4}}$$ $$\textcolor{#23d18b}{\tt{4}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_connection\_error\_is\_retryable}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_timeout\_is\_retryable}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_http\_error\_retryable\_status\_codes}}$$ $$\textcolor{#23d18b}{\tt{3}}$$ $$\textcolor{#23d18b}{\tt{3}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_http\_error\_non\_retryable\_status\_codes}}$$ $$\textcolor{#23d18b}{\tt{5}}$$ $$\textcolor{#23d18b}{\tt{5}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_http\_error\_without\_response}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_os\_error\_retryable\_errno}}$$ $$\textcolor{#23d18b}{\tt{5}}$$ $$\textcolor{#23d18b}{\tt{5}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_os\_error\_non\_retryable\_errno}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestIsRetryableError.test\_other\_exception\_not\_retryable}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCalculateDelay.test\_exponential\_backoff\_without\_jitter}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCalculateDelay.test\_exponential\_backoff\_with\_jitter}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCalculateDelay.test\_max\_delay\_cap}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCalculateDelay.test\_max\_delay\_cap\_with\_jitter}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_successful\_call\_first\_attempt}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_retry\_after\_transient\_failure}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_max\_retries\_exceeded}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_retry\_with\_custom\_predicate}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_no\_retry\_with\_predicate\_false}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryWithExponentialBackoff.test\_exception\_not\_in\_tuple\_not\_retried}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_default\_configuration}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_environment\_variable\_configuration}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_invalid\_max\_retries}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_invalid\_base\_delay}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_invalid\_multiplier}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_jitter\_values}}$$ $$\textcolor{#23d18b}{\tt{2}}$$ $$\textcolor{#23d18b}{\tt{2}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_custom\_exceptions\_only}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_custom\_predicate\_only}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_both\_exceptions\_and\_predicate}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestCreateRetryDecorator.test\_exceptions\_match\_but\_predicate\_false}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestPreconfiguredDecorators.test\_retry\_platform\_service\_call\_exists}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestPreconfiguredDecorators.test\_retry\_prompt\_service\_call\_exists}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestPreconfiguredDecorators.test\_platform\_service\_decorator\_retries\_on\_connection\_error}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestPreconfiguredDecorators.test\_prompt\_service\_decorator\_retries\_on\_timeout}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryLogging.test\_warning\_logged\_on\_retry}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryLogging.test\_info\_logged\_on\_success\_after\_retry}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{tests/utils/test\_retry\_utils.py}}$$ $$\textcolor{#23d18b}{\tt{TestRetryLogging.test\_exception\_logged\_on\_giving\_up}}$$ $$\textcolor{#23d18b}{\tt{1}}$$ $$\textcolor{#23d18b}{\tt{1}}$$
$$\textcolor{#23d18b}{\tt{TOTAL}}$$ $$\textcolor{#23d18b}{\tt{63}}$$ $$\textcolor{#23d18b}{\tt{63}}$$

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
unstract/connectors/src/unstract/connectors/filesystems/minio/minio.py (1)

27-31: ⚠️ Potential issue | 🟡 Minor

Handle one-sided static credentials explicitly.

At Line 27-Line 31, providing only one of key/secret still silently falls back to ambient auth, which can be surprising for users who intended static auth.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@unstract/connectors/src/unstract/connectors/filesystems/minio/minio.py`
around lines 27 - 31, The code silently ignores one-sided static credentials
(only key or only secret) and falls back to ambient auth; update the logic in
minio.py where creds is built so that if exactly one of key or secret is
provided (key XOR secret) you raise a clear exception (e.g., ValueError) or
return an explicit error explaining both must be supplied, rather than silently
omitting the provided value; keep the existing handling for both provided (add
both to creds) and for neither provided (keep ambient auth), and mention the
variables key, secret and creds in your change so it’s easy to locate.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@unstract/connectors/src/unstract/connectors/filesystems/minio/minio.py`:
- Around line 27-31: The code silently ignores one-sided static credentials
(only key or only secret) and falls back to ambient auth; update the logic in
minio.py where creds is built so that if exactly one of key or secret is
provided (key XOR secret) you raise a clear exception (e.g., ValueError) or
return an explicit error explaining both must be supplied, rather than silently
omitting the provided value; keep the existing handling for both provided (add
both to creds) and for neither provided (keep ambient auth), and mention the
variables key, secret and creds in your change so it’s easy to locate.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4dec7188-f37f-4473-805f-129c53fa64ad

📥 Commits

Reviewing files that changed from the base of the PR and between d930daa and d646965.

📒 Files selected for processing (2)
  • unstract/connectors/src/unstract/connectors/filesystems/minio/exceptions.py
  • unstract/connectors/src/unstract/connectors/filesystems/minio/minio.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • unstract/connectors/src/unstract/connectors/filesystems/minio/exceptions.py

@sonarqubecloud
Copy link

@kirtimanmishrazipstack kirtimanmishrazipstack changed the title UN-3343 [FEAT] Support AWS S3 storage authentication via IRSA UN-3343 [FEAT] Support AWS S3 connector authentication via IRSA Mar 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants