Skip to content

Feature/google cloud storage#316

Open
hayzie-chu wants to merge 7 commits into
Portabase:mainfrom
hayzie-chu:feature/google-cloud-storage
Open

Feature/google cloud storage#316
hayzie-chu wants to merge 7 commits into
Portabase:mainfrom
hayzie-chu:feature/google-cloud-storage

Conversation

@hayzie-chu

@hayzie-chu hayzie-chu commented Jun 10, 2026

Copy link
Copy Markdown

Closes #266

Validation Requirements screenshots:

  • “Add Storage Channel” dialog showing Google Cloud Storage as an available provider
dialog-providers
  • Google Cloud Storage configuration form in create mode
create-mode-default create-mode-filled
  • Google Cloud Storage configuration form in edit mode
edit-mode after-changed

Note: the ping/upload path hasn't been tested against a real GCS bucket yet, but the UI is fully functional

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Added Google Cloud Storage as a storage provider, including configuration UI and operations for upload, retrieval (with signed URLs), deletion, health/ping, and copying.
  • Bug Fixes

    • Expanded supported provider types in the database to include google-cloud-storage.
  • Chores

    • Updated project dependencies for Google Cloud Storage.
    • Improved local setup: added a fake GCS docker-compose, a GCS test script, and enhanced .gitignore to ignore additional local data folders and .env files.

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This pull request integrates Google Cloud Storage as a new storage provider into Portabase. It adds the @google-cloud/storage dependency, extends database schemas and TypeScript types to recognize google-cloud-storage as a valid provider, implements complete GCS operations (upload, download, delete, copy, and connectivity tests), creates configuration forms and validation schemas, and wires the provider into the existing storage dispatch system.

Changes

Google Cloud Storage Provider

Layer / File(s) Summary
Type System and Database Schema
src/features/storages/storages.types.ts, src/db/schema/12_storage-channel.ts, src/db/migrations/0058_tense_tana_nile.sql, src/db/migrations/meta/_journal.json, src/db/migrations/meta/0058_snapshot.json
StorageProviderKind union type and PostgreSQL provider_storage_kind enum extended to include google-cloud-storage with full migration metadata and schema snapshot captured.
Configuration Type and Validation Schema
src/features/channel/storages/google-cloud-storage/types.ts, src/features/channel/storages/google-cloud-storage/google-cloud-storage.schema.ts, package.json, .gitignore
GoogleCloudStorageConfig type defined with four required string fields; Zod schema validates non-empty trimmed strings and email format for clientEmail; @google-cloud/storage dependency added; .env files and emulator directories (gcs-data/, gcs-storage/) excluded from version control.
Google Cloud Storage Core Operations
src/features/channel/storages/google-cloud-storage/index.ts
GCS client initialized from config with private key newline unescaping and optional emulator endpoint; bucket verification helper; five exported async operations: uploadGoogleCloudStorage (streaming upload with content type support), getGoogleCloudStorage (with optional signed URLs expiring in configurable seconds), deleteGoogleCloudStorage, pingGoogleCloudStorage (connectivity test via write/read/delete cycle), copyGoogleCloudStorage (in-bucket object duplication).
Configuration Form Component and Schema Registration
src/features/channel/storages/google-cloud-storage/google-cloud-storage.form.tsx, src/features/channel/channel-form.schema.ts
StorageGoogleCloudStorageForm React component wires four form fields to react-hook-form with validation feedback; StorageChannelFormSchema extended with google-cloud-storage discriminated union variant mapping to GoogleCloudStorageChannelConfigSchema.
Storage Provider Dispatch and Integration
src/features/channel/channels-helpers.tsx, src/features/channel/channels-storage-helper.tsx, src/features/channel/storages/index.ts
GCS handler functions (upload, get, delete, ping, copy) registered in dispatch registry under "google-cloud-storage" key; renderChannelForm extended with google-cloud-storage case returning the form component; storageProviders list updated with value changed from "gcs" to "google-cloud-storage" and preview flag removed.
Testing and Local Development Setup
docker-compose.gcs.yml, scripts/test-gcs.ts
Docker Compose configuration defines fake-gcs-server service on port 4443 with volume mounts for persistence; test script demonstrates all five GCS operations with emulator, includes streamToString utility for reading downloaded content, and logs each operation result.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ChannelForm as Channel Form
  participant Validation as Zod Validation
  participant Dispatch as Provider Dispatch
  participant GCS as GCS Provider
  
  User->>ChannelForm: select google-cloud-storage
  User->>ChannelForm: enter projectId, bucketName, clientEmail, privateKey
  ChannelForm->>Validation: validate form data
  Validation-->>ChannelForm: validation result
  User->>ChannelForm: submit or test connection
  ChannelForm->>Dispatch: dispatch ping request
  Dispatch->>GCS: pingGoogleCloudStorage(config)
  GCS->>GCS: initialize client, verify bucket
  GCS->>GCS: write/download/delete ping.txt
  GCS-->>Dispatch: success or error
  Dispatch-->>ChannelForm: connection status
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A storage cloud so bright,
Google's keeper of our bytes,
Forms now dance with config flair,
Upload, download, copy—care!
Portabase hops with GCS might! ☁️

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Feature/google cloud storage' is vague and uses a non-descriptive format (prefix/generic term) that doesn't clearly convey the specific implementation details or main change. Use a more descriptive title like 'Add Google Cloud Storage as storage provider' that clearly summarizes the primary change and includes specific implementation details.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The pull request fully implements all required coding objectives from issue #266: provider functions, type system extension, configuration schema and form, UI integration, and database migrations for Google Cloud Storage support.
Out of Scope Changes check ✅ Passed All changes are directly related to integrating Google Cloud Storage as specified in issue #266; no unrelated modifications or scope creep detected.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

scripts/test-gcs.ts

Oops! Something went wrong! :(

ESLint: 9.39.4

TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Object'
| property 'configs' -> object with constructor 'Object'
| property 'flat' -> object with constructor 'Object'
| ...
| property 'plugins' -> object with constructor 'Object'
--- property 'react' closes the circle
Referenced from: /.eslintrc.json
at JSON.stringify ()
at /node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2255:45
at Array.map ()
at ConfigValidator.formatErrors (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2246:23)
at ConfigValidator.validateConfigSchema (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2277:84)
at ConfigArrayFactory._normalizeConfigData (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/

... [truncated 446 characters] ...

c/dist/eslintrc.cjs:3261:25)
at ConfigArrayFactory._normalizeObjectConfigDataBody (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3199:25)
(node:2) ESLintRCWarning: You are using an eslintrc configuration file, which is deprecated and support will be removed in v10.0.0. Please migrate to an eslint.config.js file. See https://eslint.org/docs/latest/use/configure/migration-guide for details. An eslintrc configuration file is used because you have the ESLINT_USE_FLAT_CONFIG environment variable set to false. If you want to use an eslint.config.js file, remove the environment variable. If you want to find the location of the eslintrc configuration file, use the --debug flag.
(Use node --trace-warnings ... to show where the warning was created)

src/features/channel/storages/google-cloud-storage/index.ts

Oops! Something went wrong! :(

ESLint: 9.39.4

TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Object'
| property 'configs' -> object with constructor 'Object'
| property 'flat' -> object with constructor 'Object'
| ...
| property 'plugins' -> object with constructor 'Object'
--- property 'react' closes the circle
Referenced from: /.eslintrc.json
at JSON.stringify ()
at /node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2255:45
at Array.map ()
at ConfigValidator.formatErrors (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2246:23)
at ConfigValidator.validateConfigSchema (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2277:84)
at ConfigArrayFactory._normalizeConfigData (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/

... [truncated 446 characters] ...

c/dist/eslintrc.cjs:3261:25)
at ConfigArrayFactory._normalizeObjectConfigDataBody (/node_modules/.pnpm/@eslint+eslintrc@3.3.5/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3199:25)
(node:2) ESLintRCWarning: You are using an eslintrc configuration file, which is deprecated and support will be removed in v10.0.0. Please migrate to an eslint.config.js file. See https://eslint.org/docs/latest/use/configure/migration-guide for details. An eslintrc configuration file is used because you have the ESLINT_USE_FLAT_CONFIG environment variable set to false. If you want to use an eslint.config.js file, remove the environment variable. If you want to find the location of the eslintrc configuration file, use the --debug flag.
(Use node --trace-warnings ... to show where the warning was created)


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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/features/channel/storages/google-cloud-storage/google-cloud-storage.schema.ts`:
- Around line 4-7: The schema currently allows whitespace-only strings and
accepts any non-empty value for clientEmail; update the validators for
projectId, bucketName, and privateKey to use z.string().trim().min(1, "...") so
whitespace-only values are rejected, and change clientEmail to
z.string().trim().min(1, "...").email("Client email must be a valid email") to
enforce a valid email format; modify the fields projectId, bucketName,
clientEmail, and privateKey in the Google Cloud Storage schema accordingly.

In `@src/features/channel/storages/google-cloud-storage/index.ts`:
- Around line 127-131: The current ping uses a fixed key "ping.txt" which can
overwrite or delete existing objects; change the logic in this block (the
bucket.file(...) usage around file.save, file.download, file.delete) to create
and use a unique temporary object name (e.g. include a timestamp/UUID:
`${BASE_DIR}ping-${Date.now()}-${uuid()}.txt`), write/download/delete that
unique key, and wrap the operations in a try/finally so you only call
file.delete() on the specific temp file you created (and catch/log errors) to
avoid touching any pre-existing objects.
- Around line 57-62: The upload wiring currently only listens to the writable
end (uploadStream.pipe(writeStream).on("finish"/"error")) which misses errors
from the readable; replace that pattern in the upload flow using the pipeline
utility (import from 'stream'/'stream/promises') and await
pipeline(uploadStream, writeStream) so both ends propagate errors reliably. Also
change pingGoogleCloudStorage so it does not use the fixed key "ping.txt" under
possibly-empty BASE_DIR; generate a namespaced/unique ping object name (e.g.,
include BASE_DIR and a UUID or timestamp like `${BASE_DIR}/.ping-<unique>.tmp`)
and only delete that exact generated key to avoid clobbering real customer
objects.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: e623b294-b1ac-4a69-84e2-34c3c1d73f30

📥 Commits

Reviewing files that changed from the base of the PR and between ebdef2d and 3765b8b.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (15)
  • .gitignore
  • package.json
  • src/db/migrations/0058_tense_tana_nile.sql
  • src/db/migrations/meta/0058_snapshot.json
  • src/db/migrations/meta/_journal.json
  • src/db/schema/12_storage-channel.ts
  • src/features/channel/channel-form.schema.ts
  • src/features/channel/channels-helpers.tsx
  • src/features/channel/channels-storage-helper.tsx
  • src/features/channel/storages/google-cloud-storage/google-cloud-storage.form.tsx
  • src/features/channel/storages/google-cloud-storage/google-cloud-storage.schema.ts
  • src/features/channel/storages/google-cloud-storage/index.ts
  • src/features/channel/storages/google-cloud-storage/types.ts
  • src/features/channel/storages/index.ts
  • src/features/storages/storages.types.ts
📜 Review details
🔇 Additional comments (14)
src/features/storages/storages.types.ts (1)

7-7: LGTM!

src/db/migrations/meta/_journal.json (1)

410-416: LGTM!

src/features/channel/storages/google-cloud-storage/types.ts (1)

1-6: LGTM!

src/features/channel/storages/google-cloud-storage/index.ts (1)

13-30: LGTM!

Also applies to: 70-113, 147-174

src/features/channel/storages/google-cloud-storage/google-cloud-storage.form.tsx (1)

1-86: LGTM!

src/features/channel/channels-helpers.tsx (1)

38-40: LGTM!

Also applies to: 102-103

src/features/channel/channels-storage-helper.tsx (1)

10-10: LGTM!

src/features/channel/storages/index.ts (1)

16-22: LGTM!

Also applies to: 53-60

src/db/schema/12_storage-channel.ts (1)

8-8: LGTM!

src/db/migrations/0058_tense_tana_nile.sql (1)

1-1: LGTM!

src/db/migrations/meta/0058_snapshot.json (1)

2731-2739: LGTM!

.gitignore (1)

31-32: LGTM!

package.json (1)

23-23: LGTM!

src/features/channel/channel-form.schema.ts (1)

12-12: LGTM!

Also applies to: 68-71

Comment thread src/features/channel/storages/google-cloud-storage/google-cloud-storage.schema.ts Outdated
Comment on lines +57 to +62
await new Promise<void>((resolve, reject) => {
uploadStream
.pipe(writeStream)
.on("finish", resolve)
.on("error", reject);
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify current upload stream wiring and absence/presence of pipeline usage.
rg -n -C3 'uploadStream|pipe\(writeStream\)|on\("finish"|on\("error"' src/features/channel/storages/google-cloud-storage/index.ts
rg -n 'pipeline\(' src/features/channel/storages/google-cloud-storage/index.ts
# Expected:
# - First command shows handlers attached through .pipe(writeStream).
# - Second command returns no matches in current code.

Repository: Portabase/portabase

Length of output: 957


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="src/features/channel/storages/google-cloud-storage/index.ts"

# Verify ping key usage and where it's used (upload/copy/delete)
rg -n "ping\.txt|ping" "$FILE"
rg -n "delete\(|remove\(|unlink\(|copy\(|rewrite\(|rename\(|bucket\.file\(" "$FILE"

# Inspect the relevant ping/copy/delete/ping method implementations with context
rg -n -C3 "ping\.txt" "$FILE"
rg -n -C5 "async function ping|ping\(" "$FILE" || true
rg -n -C5 "async function copy|copy\(" "$FILE" || true
rg -n -C5 "async function delete|delete\(|remove\(|destroy\(|unlink\(" "$FILE" || true

Repository: Portabase/portabase

Length of output: 2946


🏁 Script executed:

#!/bin/bash
set -euo pipefail
FILE="src/features/channel/storages/google-cloud-storage/index.ts"

# Check BASE_DIR definition to reason about ping key uniqueness/clobber risk
rg -n "BASE_DIR" "$FILE"
sed -n '1,220p' "$FILE" | nl -ba | sed -n '1,220p' >/tmp/gcs_top.txt || true

# Inspect upload method body for any additional error handlers on uploadStream/source
rg -n "uploadStream|writeStream|createWriteStream|Readable\.from|\.on\(\"error\"|\.once\(\"error\"" "$FILE"
# Specifically look for any handlers attached to uploadStream itself
rg -n "uploadStream.*on\(\"error\"|uploadStream.*once\(\"error\"|fileStream.*on\(\"error\"|fileStream.*once\(\"error\"" "$FILE"

# Check whether pipeline is used elsewhere in the file
rg -n "pipeline\(" "$FILE" || true

Repository: Portabase/portabase

Length of output: 816


🏁 Script executed:

#!/bin/bash
set -euo pipefail
FILE="src/features/channel/storages/google-cloud-storage/index.ts"

# Show full relevant sections with line numbers (cat -n exists even if nl doesn't)
cat -n "$FILE" | sed -n '1,120p'
cat -n "$FILE" | sed -n '120,220p'

Repository: Portabase/portabase

Length of output: 6954


Use pipeline for upload stream wiring; avoid fixed ping.txt clobber risk

  • Upload: the promise resolves/rejects only from the writable (.pipe(writeStream).on("finish"/"error")), so errors from the source/readable (uploadStream) aren’t handled reliably—use pipeline (lines 57-62).
  • Ping: BASE_DIR is "", and pingGoogleCloudStorage writes to a fixed key ping.txt and then deletes it, which can overwrite/delete an actual customer object at the same path (lines 24, 127-131).
Proposed fix (upload)
 import {Readable} from "node:stream";
+import {pipeline} from "node:stream/promises";
@@
-        await new Promise<void>((resolve, reject) => {
-            uploadStream
-                .pipe(writeStream)
-                .on("finish", resolve)
-                .on("error", reject);
-        });
+        await pipeline(uploadStream, writeStream);
📝 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
await new Promise<void>((resolve, reject) => {
uploadStream
.pipe(writeStream)
.on("finish", resolve)
.on("error", reject);
});
await pipeline(uploadStream, writeStream);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/channel/storages/google-cloud-storage/index.ts` around lines 57
- 62, The upload wiring currently only listens to the writable end
(uploadStream.pipe(writeStream).on("finish"/"error")) which misses errors from
the readable; replace that pattern in the upload flow using the pipeline utility
(import from 'stream'/'stream/promises') and await pipeline(uploadStream,
writeStream) so both ends propagate errors reliably. Also change
pingGoogleCloudStorage so it does not use the fixed key "ping.txt" under
possibly-empty BASE_DIR; generate a namespaced/unique ping object name (e.g.,
include BASE_DIR and a UUID or timestamp like `${BASE_DIR}/.ping-<unique>.tmp`)
and only delete that exact generated key to avoid clobbering real customer
objects.

Comment on lines +127 to +131
const key = `${BASE_DIR}ping.txt`;
const file = bucket.file(key);
await file.save(Buffer.from("ping"));
await file.download();
await file.delete();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid clobbering real bucket objects during ping (Lines 127-131).

Using a fixed ping.txt key can overwrite and then delete an existing object with that name, causing data loss.

Proposed fix
+import {randomUUID} from "node:crypto";
@@
-        const key = `${BASE_DIR}ping.txt`;
+        const key = `${BASE_DIR}__portabase_ping_${randomUUID()}.txt`;
         const file = bucket.file(key);
-        await file.save(Buffer.from("ping"));
-        await file.download();
-        await file.delete();
+        try {
+            await file.save(Buffer.from("ping"));
+            await file.download();
+        } finally {
+            await file.delete({ignoreNotFound: true});
+        }
📝 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
const key = `${BASE_DIR}ping.txt`;
const file = bucket.file(key);
await file.save(Buffer.from("ping"));
await file.download();
await file.delete();
const key = `${BASE_DIR}__portabase_ping_${randomUUID()}.txt`;
const file = bucket.file(key);
try {
await file.save(Buffer.from("ping"));
await file.download();
} finally {
await file.delete({ignoreNotFound: true});
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/channel/storages/google-cloud-storage/index.ts` around lines 127
- 131, The current ping uses a fixed key "ping.txt" which can overwrite or
delete existing objects; change the logic in this block (the bucket.file(...)
usage around file.save, file.download, file.delete) to create and use a unique
temporary object name (e.g. include a timestamp/UUID:
`${BASE_DIR}ping-${Date.now()}-${uuid()}.txt`), write/download/delete that
unique key, and wrap the operations in a try/finally so you only call
file.delete() on the specific temp file you created (and catch/log errors) to
avoid touching any pre-existing objects.

@LuuOW LuuOW left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Technical audit: code implementation verified for system consistency.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/features/channel/storages/google-cloud-storage/google-cloud-storage.schema.ts`:
- Around line 3-10: The GoogleCloudStorageChannelConfigSchema in this file has
duplicate syntax: the export declaration appears twice (once on line 3 and again
on line 4) and the closing brace appears twice (once on line 9 and again on line
10). Remove the first duplicate export const
GoogleCloudStorageChannelConfigSchema declaration and remove the duplicate
closing brace at the end so only one complete schema definition remains with a
single closing brace.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 27fa740f-638c-47de-bc80-d5447b58bf92

📥 Commits

Reviewing files that changed from the base of the PR and between 3765b8b and 2b58b18.

📒 Files selected for processing (1)
  • src/features/channel/storages/google-cloud-storage/google-cloud-storage.schema.ts
📜 Review details
🧰 Additional context used
🪛 Biome (2.5.0)
src/features/channel/storages/google-cloud-storage/google-cloud-storage.schema.ts

[error] 4-4: expected : but instead found const

(parse)


[error] 4-4: expected : but instead found GoogleCloudStorageChannelConfigSchema

(parse)


[error] 9-9: expected , but instead found ;

(parse)

Comment thread src/features/channel/storages/google-cloud-storage/google-cloud-storage.schema.ts Outdated
@RambokDev

Copy link
Copy Markdown
Collaborator

Hi @hayzie-chu,

Did you test with real google cloud storage ?

@RambokDev

RambokDev commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

@hayzie-chu , you could use : https://github.com/fsouza/fake-gcs-server in order to test your integration.

services:
  gcs:
    image: fsouza/fake-gcs-server:latest
    container_name: fake-gcs
    ports:
      - "4443:4443"
    command:
      - "-scheme"
      - "http"
      - "-port"
      - "4443"
      - "-public-host"
      - "localhost:4443"
      - "-external-url"
      - "http://localhost:4443"
    volumes:
      - ./gcs-data:/data
      - ./gcs-storage:/storage

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

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 current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/test-gcs.ts`:
- Around line 3-4: The seed bucket path in the commented commands on lines 3-4
uses gcs-data/test-bucket, but the emulator is configured with -filesystem-root
/storage mapped to ./gcs-storage, causing a path mismatch. Update the commented
mkdir and echo commands to use the correct path that corresponds to the
emulator's configured filesystem-root directory (./gcs-storage/test-bucket),
ensuring the bucket path used in the ping operation on line 40 matches the
seeded bucket location.
- Line 62: The main() function error handler on line 62 only logs the error
using console.error but does not exit the process with a non-zero exit code,
which may cause command runners to treat the failure as a success. Modify the
catch handler for main() to call process.exit(1) after logging the error so that
the script properly signals failure to the shell and any dependent processes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1c2e9733-3e55-4227-b2a4-6347e659d659

📥 Commits

Reviewing files that changed from the base of the PR and between 2b58b18 and f6a7cf7.

📒 Files selected for processing (5)
  • .gitignore
  • docker-compose.gcs.yml
  • scripts/test-gcs.ts
  • src/features/channel/storages/google-cloud-storage/google-cloud-storage.schema.ts
  • src/features/channel/storages/google-cloud-storage/index.ts
💤 Files with no reviewable changes (1)
  • src/features/channel/storages/google-cloud-storage/google-cloud-storage.schema.ts
📜 Review details
🔇 Additional comments (3)
.gitignore (1)

12-13: LGTM!

src/features/channel/storages/google-cloud-storage/index.ts (1)

14-18: LGTM!

docker-compose.gcs.yml (1)

1-23: LGTM!

Comment thread scripts/test-gcs.ts
Comment on lines +3 to +4
// mkdir -p gcs-data/test-bucket
// echo "hello" > gcs-data/test-bucket/seed.txt

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Seed bucket path does not match the emulator filesystem root.

Line [3]-Line [4] seed gcs-data/test-bucket, but the emulator is configured with -filesystem-root /storage (mapped to ./gcs-storage), so Line [40] can report bucket-missing on ping.

Suggested fix
-    // mkdir -p gcs-data/test-bucket
-    // echo "hello" > gcs-data/test-bucket/seed.txt
+    // mkdir -p gcs-storage/test-bucket
+    // echo "hello" > gcs-storage/test-bucket/seed.txt

Also applies to: 40-40

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/test-gcs.ts` around lines 3 - 4, The seed bucket path in the
commented commands on lines 3-4 uses gcs-data/test-bucket, but the emulator is
configured with -filesystem-root /storage mapped to ./gcs-storage, causing a
path mismatch. Update the commented mkdir and echo commands to use the correct
path that corresponds to the emulator's configured filesystem-root directory
(./gcs-storage/test-bucket), ensuring the bucket path used in the ping operation
on line 40 matches the seeded bucket location.

Comment thread scripts/test-gcs.ts
}));
}

main().catch(console.error);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Set a non-zero exit code when the script fails.

Line [62] only logs the error; command runners may still treat the run as successful.

Suggested fix
-main().catch(console.error);
+main().catch((err) => {
+  console.error(err);
+  process.exitCode = 1;
+});
📝 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
main().catch(console.error);
main().catch((err) => {
console.error(err);
process.exitCode = 1;
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/test-gcs.ts` at line 62, The main() function error handler on line 62
only logs the error using console.error but does not exit the process with a
non-zero exit code, which may cause command runners to treat the failure as a
success. Modify the catch handler for main() to call process.exit(1) after
logging the error so that the script properly signals failure to the shell and
any dependent processes.

@hayzie-chu

Copy link
Copy Markdown
Author

Hi @RambokDev, I have recently pushed a new commit with the test scripts and how to run it. I have verified that the flow works with the fake-gcs-server.

@RambokDev

Copy link
Copy Markdown
Collaborator

Hi @RambokDev, I have recently pushed a new commit with the test scripts and how to run it. I have verified that the flow works with the fake-gcs-server.

Ok, nice. I’ll take a look at that and come back to you if I have any questions.

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.

Integrate Google Cloud Storage for storage backend

3 participants