feat(aurora): add CORS configuration management for Ceph/S3 buckets - #1092
feat(aurora): add CORS configuration management for Ceph/S3 buckets#1092KirylSAP wants to merge 6 commits into
Conversation
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughAdds Ceph bucket CORS schemas, get/set/delete APIs, validation, rule-management components, bucket actions, modal flows, notifications, status loading, tests, and English/German translation entries. ChangesCeph bucket CORS management
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant BucketHeader
participant CorsModal
participant corsRouter
participant CephS3
User->>BucketHeader: Open or edit CORS
BucketHeader->>CorsModal: Open modal
CorsModal->>corsRouter: Load CORS rules
corsRouter->>CephS3: GetBucketCorsCommand
CephS3-->>corsRouter: CORS configuration
corsRouter-->>CorsModal: Validated rules
User->>CorsModal: Save or delete configuration
CorsModal->>corsRouter: Set or delete CORS
corsRouter->>CephS3: PutBucketCorsCommand or DeleteBucketCorsCommand
CephS3-->>corsRouter: Operation result
corsRouter-->>CorsModal: Success or mapped error
Possibly related issues
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (1)
packages/aurora/src/server/Storage/routers/ceph/corsRouter.test.ts (1)
70-190: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a
gettest for a stored rule that violates the write schema. Allgettests feed rules that satisfycorsRuleSchema. There's no case where S3 returns e.g.MaxAgeSeconds > 86400, which currently makesgetfail (see the read-validation issue incorsRouter.ts). A test here would pin down the intended behavior once that's resolved.🤖 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 `@packages/aurora/src/server/Storage/routers/ceph/corsRouter.test.ts` around lines 70 - 190, The get test suite lacks coverage for stored CORS rules that violate corsRuleSchema, such as a rule with MaxAgeSeconds greater than 86400. Add a caller.get test using mockSend with an otherwise valid rule containing this out-of-range value, and assert the intended successful read behavior after the corsRouter.ts validation fix.
🤖 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
`@packages/aurora/src/client/routes/_auth/projects/`$projectId/storage/-components/Ceph/Buckets/BucketModals.tsx:
- Around line 137-150: Update the CorsModal callback handling in BucketModals so
save and delete operations select distinct success and error toasts. Split the
callbacks or propagate the completed operation from CorsModal, then use
deletion-specific toast helpers for deleting all rules while preserving the
existing save toasts for save operations.
In
`@packages/aurora/src/client/routes/_auth/projects/`$projectId/storage/-components/Ceph/Buckets/CorsModal.tsx:
- Around line 113-115: Update the CorsRuleForm rendering to use a React key
based on the current editing target, such as the editing rule index or null
state, so canceling via handleCancelEdit remounts the form and clears stale
values. Apply the change at the <CorsRuleForm> usage rather than modifying
handleCancelEdit.
In
`@packages/aurora/src/client/routes/_auth/projects/`$projectId/storage/-components/Ceph/Buckets/CorsRuleForm.tsx:
- Around line 16-40: The CorsRuleForm retains stale edit values after
cancellation because its defaultValues are only applied on initial mount. Update
the CorsRuleForm usage or its lifecycle so canceling and setting editingRule to
null remounts it with a distinct key or resets all fields to blank defaults,
while preserving the existing values when editing a rule.
In
`@packages/aurora/src/client/routes/_auth/projects/`$projectId/storage/-components/Ceph/Buckets/CorsRulesViewer.tsx:
- Around line 36-39: Replace the manual rule/rules ternary in the surrounding
Trans block with Lingui’s Plural macro/component, passing rules.length as the
plural count so translators control localized wording and word order; apply the
same change to the minute/minutes message around the related duration display,
and preserve the existing counts and surrounding UI behavior.
- Around line 59-65: Update the warning Message in CorsRulesViewer to use the
useLingui() t macro for its title, matching the translated title behavior in
CorsModal.tsx while preserving the existing warning content and styling.
In
`@packages/aurora/src/client/routes/_auth/projects/`$projectId/storage/-components/Ceph/Buckets/DeleteCorsModal.tsx:
- Around line 129-135: Update the CORS count message in DeleteCorsModal to use
Lingui’s Plural component instead of the inline rule/rules ternary. Bind the
corsRules.length value through the count binding and provide locale-aware
one/other plural forms without interpolating the count directly into the one
prop.
In
`@packages/aurora/src/client/routes/_auth/projects/`$projectId/storage/-components/Ceph/Buckets/TagInput.tsx:
- Around line 97-111: The urlValidator currently rejects wildcard-subdomain
origins because URL parsing does not accept * in hostnames. Update urlValidator
to validate http://*.example.com and https://*.example.com forms using
wildcard-safe parsing, while continuing to require only http: or https:
protocols and preserving existing validation results for ordinary URLs.
In `@packages/aurora/src/server/Storage/routers/ceph/corsRouter.ts`:
- Around line 44-67: Update the CORS read path around the rawCorsRules mapping
so GET operations do not parse stored rules with the write-only corsRuleSchema.
Use a lenient read schema or safe per-rule parsing that accepts valid S3/Ceph
values, including larger MaxAgeSeconds and longer AllowedMethods collections,
while preserving the existing null and error handling behavior.
---
Nitpick comments:
In `@packages/aurora/src/server/Storage/routers/ceph/corsRouter.test.ts`:
- Around line 70-190: The get test suite lacks coverage for stored CORS rules
that violate corsRuleSchema, such as a rule with MaxAgeSeconds greater than
86400. Add a caller.get test using mockSend with an otherwise valid rule
containing this out-of-range value, and assert the intended successful read
behavior after the corsRouter.ts validation fix.
🪄 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: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 97cfcf9f-87c6-476a-9e46-739e2df9a805
📒 Files selected for processing (20)
packages/aurora/src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/BucketHeader.tsxpackages/aurora/src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/BucketHeaderActions.tsxpackages/aurora/src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/BucketModals.tsxpackages/aurora/src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/BucketToastNotifications.tsxpackages/aurora/src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/CorsModal.tsxpackages/aurora/src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/CorsRuleForm.tsxpackages/aurora/src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/CorsRulesViewer.tsxpackages/aurora/src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/DeleteCorsModal.tsxpackages/aurora/src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/TagInput.tsxpackages/aurora/src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/hooks/useBucketInfo.tspackages/aurora/src/locales/de/messages.popackages/aurora/src/locales/de/messages.tspackages/aurora/src/locales/en/messages.popackages/aurora/src/locales/en/messages.tspackages/aurora/src/server/Storage/helpers/s3ErrorMapper.tspackages/aurora/src/server/Storage/routers/ceph/corsRouter.test.tspackages/aurora/src/server/Storage/routers/ceph/corsRouter.tspackages/aurora/src/server/Storage/routers/ceph/index.tspackages/aurora/src/server/Storage/routers/index.tspackages/aurora/src/server/Storage/types/ceph.ts
| <CorsModal | ||
| isOpen={activeModal === "cors"} | ||
| bucketName={bucketName} | ||
| onClose={onClose} | ||
| onSuccess={(bucketName) => { | ||
| const { message, ...options } = getCorsSavedToast(bucketName) | ||
| toast.success(message, options) | ||
| onClose() | ||
| }} | ||
| onError={(bucketName, errorMessage) => { | ||
| const { message, ...options } = getCorsSaveErrorToast(bucketName, errorMessage) | ||
| toast.error(message, options) | ||
| onClose() | ||
| }} |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Report editor-initiated deletion as deletion.
CorsModal calls these callbacks for both saving and deleting all rules. Its delete path therefore displays “CORS Configuration Saved” or a save-error toast. Split save/delete callbacks, or pass the completed operation, and select the matching toast.
🤖 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
`@packages/aurora/src/client/routes/_auth/projects/`$projectId/storage/-components/Ceph/Buckets/BucketModals.tsx
around lines 137 - 150, Update the CorsModal callback handling in BucketModals
so save and delete operations select distinct success and error toasts. Split
the callbacks or propagate the completed operation from CorsModal, then use
deletion-specific toast helpers for deleting all rules while preserving the
existing save toasts for save operations.
| const handleCancelEdit = () => { | ||
| setEditingRuleIndex(null) | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Root cause of stale form values is in CorsRuleForm.tsx.
See the review comment on CorsRuleForm.tsx (lines 16-40): calling onCancel here changes editingRule from a rule object to null without remounting CorsRuleForm, so the form doesn't reset. Consolidated fix is to key <CorsRuleForm> by the editing target (line 232).
🤖 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
`@packages/aurora/src/client/routes/_auth/projects/`$projectId/storage/-components/Ceph/Buckets/CorsModal.tsx
around lines 113 - 115, Update the CorsRuleForm rendering to use a React key
based on the current editing target, such as the editing rule index or null
state, so canceling via handleCancelEdit remounts the form and clears stale
values. Apply the change at the <CorsRuleForm> usage rather than modifying
handleCancelEdit.
| export const CorsRuleForm = ({ editingRule, onSubmit, onCancel, isSaving }: CorsRuleFormProps) => { | ||
| const { t } = useLingui() | ||
|
|
||
| const form = useForm({ | ||
| defaultValues: { | ||
| ID: editingRule?.ID || "", | ||
| AllowedOrigins: editingRule?.AllowedOrigins || [], | ||
| AllowedMethods: (editingRule?.AllowedMethods || []) as string[], | ||
| AllowedHeaders: editingRule?.AllowedHeaders || [], | ||
| ExposeHeaders: editingRule?.ExposeHeaders || [], | ||
| MaxAgeSeconds: editingRule?.MaxAgeSeconds?.toString() || "", | ||
| }, | ||
| onSubmit: async ({ value }) => { | ||
| const newRule: CorsRule = { | ||
| ID: value.ID || undefined, | ||
| AllowedOrigins: value.AllowedOrigins, | ||
| AllowedMethods: value.AllowedMethods as ("GET" | "PUT" | "POST" | "DELETE" | "HEAD")[], | ||
| AllowedHeaders: value.AllowedHeaders.length > 0 ? value.AllowedHeaders : undefined, | ||
| ExposeHeaders: value.ExposeHeaders.length > 0 ? value.ExposeHeaders : undefined, | ||
| MaxAgeSeconds: value.MaxAgeSeconds ? parseInt(value.MaxAgeSeconds, 10) : undefined, | ||
| } | ||
|
|
||
| onSubmit(newRule) | ||
| }, | ||
| }) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Locate relevant files =="
fd -a 'Cors(RuleForm|Modal)\.tsx$|CorsRuleForm\.tsx$|CorsModal\.tsx$' . || true
echo "== Search for CorsRuleForm definition and CorsModal usages =="
rg -n "CorsRuleForm|handleCancelEdit|editingRule|activeTab|Tab\.ADD" -S . --glob '*.tsx' --glob '*.ts' | head -200
echo "== Git diff stat/name-only (context) =="
git diff --stat || true
git diff --name-only || trueRepository: cobaltcore-dev/aurora-dashboard
Length of output: 10006
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== CorsModal outline/contents =="
wc -l packages/aurora/src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/CorsModal.tsx
sed -n '1,270p' packages/aurora/src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/CorsModal.tsx
echo "== CorsRuleForm relevant contents =="
sed -n '1,80p' packages/aurora/src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/CorsRuleForm.tsx
sed -n '160,185p' packages/aurora/src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/CorsRuleForm.tsx
echo "== Package lock files/deps mentioning `@tanstack/react-form` =="
rg -n '"`@tanstack/react-form`"|`@tanstack/react-form`' package.json pnpm-lock.yaml package-lock.json yarn.lock 2>/dev/null || trueRepository: cobaltcore-dev/aurora-dashboard
Length of output: 244
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== CorsModal contents =="
wc -l 'packages/aurora/src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/CorsModal.tsx'
sed -n '1,270p' 'packages/aurora/src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/CorsModal.tsx'
echo "== CorsRuleForm relevant contents =="
sed -n '1,80p' 'packages/aurora/src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/CorsRuleForm.tsx'
sed -n '160,185p' 'packages/aurora/src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/CorsRuleForm.tsx'
echo "== Package lock files/deps mentioning `@tanstack/react-form` =="
rg -n '"`@tanstack/react-form`"|`@tanstack/react-form`' package.json pnpm-lock.yaml package-lock.json yarn.lock 2>/dev/null || true
echo "== Behavioral/static verifier: tab-cancel flow and Form call site =="
python3 - <<'PY'
from pathlib import Path
p = Path('packages/aurora/src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/CorsModal.tsx')
text = p.read_text()
checks = {
'handleCancelEdit': 'const handleCancelEdit' in text,
'sets editingRuleIndex null': 'setEditingRuleIndex(null)' in text,
'activeTab unchanged in handleCancelEdit': 'handleCancelEdit' in text and text.split('const handleCancelEdit')[1].split('};')[0].lsplit('const handleDelete')[0] is not None and 'setActiveTab' not in text.split('const handleCancelEdit')[1].split('};')[0],
'CorsRuleForm mounted in activeTab ADD': '<CorsRuleForm' in text and 'activeTab === Tab.ADD' in text,
'editingRule prop keyed by nullity only': 'editingRule={editingRuleIndex !== null ? currentRules[editingRuleIndex] : null}' in text,
'form key absent': 'key=' not in text.split('<CorsRuleForm', 1)[1].split('/')[0],
}
for k,v in checks.items():
print(f'{k}: {v}')
PYRepository: cobaltcore-dev/aurora-dashboard
Length of output: 12151
🌐 Web query:
TanStack Form v1 useForm defaultValues prop changes do not reset form unless remount reset
💡 Result:
In TanStack Form v1, issues where defaultValues prop changes do not automatically reset the form or where form.reset() behaves inconsistently often stem from how the library manages internal state and options synchronization, particularly within the React adapter [1][2][3]. If you find that your form is not resetting as expected when defaultValues change, consider the following points: 1. Reactivity and useMemo: The documentation emphasizes that if the defaultValues object changes, the form state will be reset to the new values [4]. To prevent unnecessary or incorrect resets, it is critical to use React.useMemo when defining your defaultValues object, ensuring it only changes when the underlying data actually changes [4]. 2. Reset Behavior Issues: Historically, there have been issues where calling form.reset(values) inside asynchronous functions (such as onSubmit) or when prop-driven updates occur caused the form to revert to the initial defaultValues instead of the new ones provided [1][2][3]. These behaviors have been addressed in various patch releases (e.g., v1.14.1 and subsequent fixes) aimed at ensuring reset() and update() honor the intended values [1][2][3]. If you are experiencing this, ensure you are using the latest version of the library. 3. Using form.reset() explicitly: If you need to force a reset to new values, the form.reset(newValues) method is the intended API [5]. If you want to change the defaults but maintain the current state, or vice versa, you can provide options to reset(values, { keepDefaultValues: ... }) [5]. 4. Workarounds: If your form remains "stuck" due to stale options during re-renders, some developers have found that ensuring the form instance is properly updated or, in extreme cases, remounting the component (using a key prop) forces a clean initialization [1][3]. However, with recent fixes to FormApi—such as the introduction of internal flags to track when default values have been overridden—the library should now correctly preserve values even when subsequent re-renders occur [3]. If you are still facing persistent issues, check the TanStack Form repository for the latest bug reports related to your specific framework adapter, as these issues are often environment-specific [6][7].
Citations:
- 1: form.reset(value) is not resetting defaultValues to a provided value TanStack/form#1490
- 2: Bug: form.reset(value) seems not caring about value. It's reseting to the defaultValues anyway. TanStack/form#1485
- 3: fix(form-core): preserve reset(newValues) when update() is called with stale options TanStack/form#2218
- 4: https://github.com/TanStack/form/blob/master/docs/api.md
- 5: https://mintlify.wiki/tanstack/form/api/core/form-api
- 6:
defaultValuesnot being propagated correctly upon callingresetTanStack/form#1139 - 7: Reset form doesn't work properly when initial value comes from props TanStack/form#1835
🌐 Web query:
TanStack Form @tanstack/react-form 1.29.0 source defaultValues useEffect useDefaultValues change form reset
💡 Result:
In TanStack Form (including version 1.29.0), managing defaultValues and form state requires careful handling to ensure reactivity and state consistency [1][2]. When you need to update the default values of a form (e.g., after a successful API save to reset the "dirty" state), you can use the form.reset method [3]. Calling form.reset(newDefaultValues) updates the form's internal baseline values to those provided [3]. If you are experiencing issues where default values appear to be "lagging" or reverting, consider the following technical nuances: 1. Reactivity and Rerenders: TanStack Form uses a store-based reactivity model [1]. If you need a component to react to updates in default values or dirty state, ensure you are utilizing the provided subscription methods (like form.Subscribe or useStore) rather than relying on direct access to formApi.options [1]. 2. Race Conditions: Issues have been observed where calling form.reset inside an onSubmit handler can lead to race conditions where the internal state is overwritten by subsequent updates [2]. If form.reset is failing to reflect your new values, a common workaround identified by the community is to wrap the reset call in a setTimeout, though this is a symptom of internal state synchronization and not a permanent architectural solution [2]. 3. Updating Options Safely: If you use form.update to change default values, be aware that it replaces the entire options object [4]. To safely update defaultValues without losing other configurations like onSubmit or validators, you must spread the existing options: form.update({...form.options, defaultValues: newValues }) [4] The concept of a useDefaultValues hook does not exist as a native feature in the public TanStack Form API; instead, the lifecycle of default values is managed directly via the form instance methods reset and update [3][4]. If you find your values are not updating as expected, ensure you are not triggering form updates in a way that conflicts with ongoing submission processes [2].
Citations:
- 1:
defaultValuesnot being propagated correctly upon callingresetTanStack/form#1139 - 2: form.reset during onSubmit ignores new default values TanStack/form#1681
- 3: https://mintlify.wiki/tanstack/form/api/core/form-api
- 4: form.update() silently wipes onSubmit and other options - need way to update defaultValues safely TanStack/form#1988
🌐 Web query:
github TanStack form packages react form useForm defaultValues remount source
💡 Result:
In TanStack Form, the defaultValues provided to the useForm hook are intended to be the initial state of the form [1][2]. If these defaultValues change, the form's internal state will typically be reset to the new values [3]. Regarding behavior during remounts and updates: 1. Initialization: When the component calling useForm mounts, the form is initialized with the provided defaultValues [4][3]. 2. Updating defaultValues: Because the useForm hook integrates with React's lifecycle, if the defaultValues object passed to the hook changes (e.g., due to a parent re-render with new props or fetched data), TanStack Form detects this change and updates the form's state accordingly [3]. It is recommended to use useMemo for the defaultValues object to prevent unnecessary re-initializations [3]. 3. Remounting: If the component calling useForm unmounts and remounts, the useForm hook will run again, creating a fresh FormApi instance [5]. Consequently, the form state will be reset to the current defaultValues. If you need to "reset" a form while keeping it mounted, you should use the form.reset() method [3][6]. 4. Known Issues and Workarounds: - A common issue arises when form.reset(newValues) is called (e.g., inside an onSubmit handler), but the form subsequently reverts to the original defaultValues due to a re-render where the component's useForm options are re-evaluated [6][7]. This is because the component closure may still hold the "stale" original defaultValues. - Recent patches (e.g., PR #2218) have introduced internal flags (like _defaultValuesOverridden) to prevent this regression, ensuring that explicit calls to reset(newValues) are preserved even when the component re-renders with stale options [7]. - If you are experiencing unexpected resets, ensure you are not passing a non-memoized object as defaultValues and consider using the { keepDefaultValues: true } option if you wish to treat the new values as the new base defaults [8]. For handling asynchronous data, TanStack documentation suggests avoiding manual useEffect synchronizations where possible and instead leveraging the defaultValues prop directly or coordinating with data-fetching libraries like TanStack Query [9][4].
Citations:
- 1: https://tanstack.com/form/latest/docs/framework/react/reference/functions/useForm
- 2: https://tanstack.com/form/latest/docs/reference/interfaces/FormOptions
- 3: https://github.com/TanStack/form/blob/master/docs/api.md
- 4: https://stackoverflow.com/questions/77272852/react-use-form-not-updating-the-form-default-values-on-api-response
- 5: https://github.com/TanStack/form/blob/main/packages/react-form/src/useForm.tsx
- 6: form.reset(value) is not resetting defaultValues to a provided value TanStack/form#1490
- 7: fix(form-core): preserve reset(newValues) when update() is called with stale options TanStack/form#2218
- 8: Reset form does not work as expected in combination with
useStoreTanStack/form#1798 - 9: https://tanstack.com/form/v1/docs/framework/react/guides/async-initial-values
🌐 Web query:
site:github.com/tanstack/form@1.29.0 packages/react-form src useForm.tsx
💡 Result:
The file packages/react-form/src/useForm.tsx is a core component of the TanStack Form library for React [1][2]. It defines the useForm custom React hook, which serves as the primary entry point for managing form state, handling submissions, and interacting with form fields within a React application [3][4]. Key technical aspects of this file include: 1. Functionality: The hook returns an extended instance of the FormApi class, which encapsulates the form's logic, including state management and field interactions [3][4]. 2. Implementation: It leverages TanStack Form's core functionality (from @tanstack/form-core) and provides React-specific extensions, such as integration with React's lifecycle and rendering patterns (e.g., useMemo, useState, and useIsomorphicLayoutEffect) [1][5]. 3. API: It accepts optional form configuration (FormOptions) and returns a ReactFormExtendedApi, which includes utilities like handleSubmit, formId, and the current form state [1][3][6]. This file is central to the library's architecture, bridging the framework-agnostic core logic with React-specific components like Field and Subscribe [7][5].
Citations:
- 1: https://github.com/TanStack/form/blob/main/packages/react-form/src/useForm.tsx
- 2: https://github.com/TanStack/form/blob/254f157e/packages/react-form/src/useForm.tsx
- 3: https://tanstack.com/form/v1/docs/framework/react/reference/functions/useForm
- 4: https://tanstack.com/form/latest/docs/framework/react/reference/functions/useForm
- 5: https://github.com/TanStack/form/blob/c8814d9e/packages/react-form/src/useForm.tsx
- 6: https://tanstack.dev/form/v1/docs/framework/react/reference/functions/useForm
- 7: https://tanstack.com/form/v1/docs/framework/react/reference/interfaces/ReactFormApi
🌐 Web query:
@tanstack/form-core 1.29.0 defaultValues sync formApi.options defaultValues reset
💡 Result:
In @tanstack/form-core version 1.29.0, the relationship between defaultValues, formApi.options, and the reset method is governed by a prioritize-field-over-form strategy and specific mechanisms to ensure state consistency [1][2]. Core Reset Behavior When you call form.reset(values, opts), the behavior depends on the parameters provided: - If values are passed and keepDefaultValues is false (default), the form updates its internal formApi.options.defaultValues to the new values and resets the form state to those new values [3][4]. - If no values are passed, the form resets to the current baseline defaults [3][4]. Field-over-Form Prioritization As of the 1.29.0 release cycle, TanStack Form employs a prioritized default system [1][2]: - When calculating default values (e.g., for form.reset or deriving isDefaultValue), the library prioritizes field-level default values (defined on individual field instances) over form-level default values (defined in form options) [2]. - This ensures that when the form resets, it respects the specific default values configured at the field level, preventing "reset betrayal" where form-level defaults unexpectedly override field-specific ones [2]. State Synchronization and Overwrite Prevention TanStack Form includes mechanisms to prevent stale component props from overriding a manual reset: - When reset(newValues) is called, it sets an internal flag (e.g., _defaultValuesOverridden) to signal that the user has explicitly changed the baseline defaults [5]. - During subsequent updates (often triggered by framework re-renders), the form checks this flag to prevent the adapter from overwriting the recently reset values with stale ones from the original component props [6][5]. This ensures that values set via reset persist even if the component re-renders with its original default prop [6][5]. If you find that defaultValues are "lagging" or reverting unexpectedly, it is typically due to React (or other framework) adapters re-rendering with stale options, which the library actively attempts to guard against in recent patches like 1.29.0 [6][5][7].
Citations:
- 1: https://github.com/TanStack/form/blob/main/packages/form-core/CHANGELOG.md
- 2: fix(form-core): establish Field-over-Form prioritization for isDefaultValue and resets TanStack/form#2006
- 3: https://github.com/TanStack/form/blob/main/packages/form-core/src/FormApi.ts
- 4: https://mintlify.wiki/tanstack/form/api/core/form-api
- 5: fix(form-core): preserve reset(newValues) when update() is called with stale options TanStack/form#2218
- 6: fix(form-core): prevent reset(newValues) being overwritten by subsequent update() TanStack/form#2215
- 7: form.reset(value) is not resetting defaultValues to a provided value TanStack/form#1490
Reset CorsRuleForm when canceling edit.
handleCancelEdit only clears editingRuleIndex; activeTab stays on Tab.ADD, so the <CorsRuleForm> mount with stale defaultValues is reused. The form continues showing the edited rule’s values after canceled edit. Add a key on the <CorsRuleForm> based on the edit target, or reset the form to blank values when editingRule becomes null.
🤖 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
`@packages/aurora/src/client/routes/_auth/projects/`$projectId/storage/-components/Ceph/Buckets/CorsRuleForm.tsx
around lines 16 - 40, The CorsRuleForm retains stale edit values after
cancellation because its defaultValues are only applied on initial mount. Update
the CorsRuleForm usage or its lifecycle so canceling and setting editingRule to
null remounts it with a distinct key or resets all fields to blank defaults,
while preserving the existing values when editing a rule.
| <Trans> | ||
| {rules.length} {rules.length === 1 ? "rule" : "rules"} configured | ||
| </Trans> | ||
| )} |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Hardcoded pluralization words bypass i18n (see also line 206-210).
rules.length === 1 ? "rule" : "rules" is passed as an interpolated value inside <Trans>, so translators only ever see the generic "{0} {1} configured" message and the English words "rule"/"rules" are baked in verbatim for every locale — German (and others) can't render correct pluralization/word order. Use Lingui's Plural macro/component instead of a manual ternary. The same pattern recurs for "minute"/"minutes" at lines 206-210; see consolidated note.
Static analysis also flags this line ("Should be ${variable}, not ${object.property} or ${myFunction()}"), and the same rule additionally flags index + 1 at line 132 (lower-impact, since that's just a numeric placeholder).
🧰 Tools
🪛 GitHub Check: lint
[warning] 37-37:
Should be ${variable}, not ${object.property} or ${myFunction()}
[warning] 37-37:
Should be ${variable}, not ${object.property} or ${myFunction()}
🤖 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
`@packages/aurora/src/client/routes/_auth/projects/`$projectId/storage/-components/Ceph/Buckets/CorsRulesViewer.tsx
around lines 36 - 39, Replace the manual rule/rules ternary in the surrounding
Trans block with Lingui’s Plural macro/component, passing rules.length as the
plural count so translators control localized wording and word order; apply the
same change to the minute/minutes message around the related duration display,
and preserve the existing counts and surrounding UI behavior.
Source: Linters/SAST tools
| <Message variant="warning" title="Security Warning" className="mb-4"> | ||
| <Trans> | ||
| One or more rules use wildcard (*) for AllowedOrigins, which allows any website to access your bucket. Only | ||
| use this for truly public resources. | ||
| </Trans> | ||
| </Message> | ||
| )} |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Hardcoded title="Security Warning" is never translated.
Unlike the equivalent warning in CorsModal.tsx (title={t\Security Warning`}), this titleis a plain string literal, so it will always render in English regardless of locale even though a "Security Warning" catalog entry exists. Use theuseLingui() t` macro here too.
🌐 Proposed fix
+import { Trans, useLingui } from "`@lingui/react/macro`"
...
export const CorsRulesViewer = ({...}: CorsRulesViewerProps) => {
+ const { t } = useLingui()
const hasWildcardOrigin = rules.some((rule) => rule.AllowedOrigins.includes("*"))
...
- <Message variant="warning" title="Security Warning" className="mb-4">
+ <Message variant="warning" title={t`Security Warning`} className="mb-4">📝 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.
| <Message variant="warning" title="Security Warning" className="mb-4"> | |
| <Trans> | |
| One or more rules use wildcard (*) for AllowedOrigins, which allows any website to access your bucket. Only | |
| use this for truly public resources. | |
| </Trans> | |
| </Message> | |
| )} | |
| <Message variant="warning" title={t`Security Warning`} className="mb-4"> | |
| <Trans> | |
| One or more rules use wildcard (*) for AllowedOrigins, which allows any website to access your bucket. Only | |
| use this for truly public resources. | |
| </Trans> | |
| </Message> | |
| )} |
🤖 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
`@packages/aurora/src/client/routes/_auth/projects/`$projectId/storage/-components/Ceph/Buckets/CorsRulesViewer.tsx
around lines 59 - 65, Update the warning Message in CorsRulesViewer to use the
useLingui() t macro for its title, matching the translated title behavior in
CorsModal.tsx while preserving the existing warning content and styling.
| {corsData?.corsRules && ( | ||
| <p className="text-theme-default text-sm"> | ||
| <Trans> | ||
| Current configuration has {corsData.corsRules.length} CORS{" "} | ||
| {corsData.corsRules.length === 1 ? "rule" : "rules"}. | ||
| </Trans> | ||
| </p> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
file="packages/aurora/src/client/routes/_auth/projects/\$projectId/storage/-components/Ceph/Buckets/DeleteCorsModal.tsx"
echo "== file exists =="
if [ -f "$file" ]; then echo yes; wc -l "$file"; else echo no; fi
echo "== relevant file excerpt =="
sed -n '1,190p' "$file"
echo "== Lingui plural usage in same repo =="
rg -n "Plural|count=|pluralized|i18n|macro" packages/aurora/src -g '*.tsx' -g '*.ts' | head -200
echo "== inline ternary message occurrences =="
rg -n '\? ".*\. ?" : ".*\. ?"|rule" : "rules|Plural' packages/aurora/src/client/routes/_auth/projects/"$projectId"/storage/-components/Ceph/Buckets/DeleteCorsModal.tsx packages/aurora/src/client/routes/_auth/projects -g '*.tsx' -g '*.ts' | head -200 || trueRepository: cobaltcore-dev/aurora-dashboard
Length of output: 32298
🌐 Web query:
Lingui Plural component documentation value one other
💡 Result:
In LinguiJS, the Plural component is used to handle quantity-dependent messages [1][2]. It requires a value prop and an other prop, which serves as the required catch-all plural form [3][1]. When using the Plural component: - value: Specifies the number used to determine the plural form [3][1]. - one: Represents the singular form (e.g., used for "1") [3][1]. - other: The required general plural form (used if no other specific rule matches) [3][1]. - #: A special placeholder that is automatically replaced with the actual value of the value prop [2]. Example usage: Beyond one and other, you may use other CLDR-compliant categories such as zero, two, few, or many, depending on the requirements of the target language [3][4]. Additionally, you can handle exact numeric matches by using props prefixed with an underscore, such as _0 for "0" or _1 for "1" [1][2]. Exact matches take precedence over category-based plural forms [2][5].
Citations:
- 1: https://lingui.dev/ref/macro
- 2: https://github.com/lingui/skills/blob/HEAD/lingui-best-practices/SKILL.md
- 3: https://lingui.dev/guides/plurals
- 4: https://phrase.com/blog/posts/localizing-javascript-react-apps-with-linguijs/
- 5: https://lingui-for.roundtrip.dev/macros/plural
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== lint config references for lingui/localized strings =="
rg -n "localized|localization|lingui|I18n|Plural|rule" -g '*lint*' -g '*eslintrc*' -g '*.json' -g '*.js' -g '*.mjs' . \
| head -300 || true
echo "== examples of Plural with bound count in storage components =="
sed -n '1,40p' "packages/aurora/src/client/routes/_auth/projects/\$projectId/storage/-components/Swift/Objects/index.tsx"
sed -n '100,118p' "packages/aurora/src/client/routes/_auth/projects/\$projectId/storage/-components/Swift/Objects/DeleteObjectsModal.tsx"
sed -n '105,120p' "packages/aurora/src/client/routes/_auth/projects/\$projectId/storage/-components/Swift/Containers/ContainerToastNotifications.tsx"
echo "== deterministic Lingui Plural semantic probe =="
node - <<'JS'
const pluralForm = {
one: "rule",
other: "rules",
}
for (const n of [0, 1, 2, 3]) {
const form = n === 1 ? "one" : "other"
// Lingui's simplest English Plural behavior for one/other.
console.log(`${n}: ${form === "one" ? pluralForm.one : pluralForm.other}`)
}
JSRepository: cobaltcore-dev/aurora-dashboard
Length of output: 35739
Use Lingui pluralization for the CORS rule count.
The inline English ternary won’t use locale-specific plural forms. Bind the count and replace it with Plural; avoid interpolating the count directly into the one prop so the value is handled by Plural.
Proposed fix
-import { Trans, useLingui } from "`@lingui/react/macro`"
+import { Plural, Trans, useLingui } from "`@lingui/react/macro`"
...
+ const corsRuleCount = corsData?.corsRules?.length ?? 0
...
- Current configuration has {corsData.corsRules.length} CORS{" "}
- {corsData.corsRules.length === 1 ? "rule" : "rules"}.
+ Current configuration has {corsRuleCount} CORS{" "}
+ <Plural value={corsRuleCount} one="rule" other="rules" />.📝 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.
| {corsData?.corsRules && ( | |
| <p className="text-theme-default text-sm"> | |
| <Trans> | |
| Current configuration has {corsData.corsRules.length} CORS{" "} | |
| {corsData.corsRules.length === 1 ? "rule" : "rules"}. | |
| </Trans> | |
| </p> | |
| {corsData?.corsRules && ( | |
| <p className="text-theme-default text-sm"> | |
| <Trans> | |
| Current configuration has {corsRuleCount} CORS{" "} | |
| <Plural value={corsRuleCount} one="rule" other="rules" />. | |
| </Trans> | |
| </p> |
🧰 Tools
🪛 GitHub Check: lint
[warning] 133-133:
Should be ${variable}, not ${object.property} or ${myFunction()}
[warning] 132-132:
Should be ${variable}, not ${object.property} or ${myFunction()}
🤖 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
`@packages/aurora/src/client/routes/_auth/projects/`$projectId/storage/-components/Ceph/Buckets/DeleteCorsModal.tsx
around lines 129 - 135, Update the CORS count message in DeleteCorsModal to use
Lingui’s Plural component instead of the inline rule/rules ternary. Bind the
corsRules.length value through the count binding and provide locale-aware
one/other plural forms without interpolating the count directly into the one
prop.
Source: Linters/SAST tools
| export const urlValidator = (url: string): { valid: boolean; error?: string } => { | ||
| if (url === "*") { | ||
| return { valid: true } | ||
| } | ||
|
|
||
| try { | ||
| const urlObj = new URL(url) | ||
| if (!["http:", "https:"].includes(urlObj.protocol)) { | ||
| return { valid: false, error: "URL must use http or https protocol" } | ||
| } | ||
| return { valid: true } | ||
| } catch { | ||
| return { valid: false, error: "Invalid URL format. Expected: https://example.com" } | ||
| } | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Locate file =="
fd -a 'TagInput.tsx$' . || true
echo "== Relevant file excerpt =="
if [ -f packages/aurora/src/client/routes/_auth/projects/\$projectId/storage/-components/Ceph/Buckets/TagInput.tsx ]; then
sed -n '1,180p' packages/aurora/src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/TagInput.tsx | cat -n
fi
echo "== Search urlValidator usages =="
rg -n "urlValidator|AllowedOrigin|CORS|cors" packages/aurora/src || true
echo "== JS URL behavior for wildcard candidates =="
node - <<'JS'
const cases = [
"*",
"http://*.example.com",
"https://*.example.com",
"http://example.com",
"file://*.example.com",
"http://a*b.example.com"
];
for (const url of cases) {
let status = "allowed";
try {
const u = new URL(url);
if (!["http:", "https:"].includes(u.protocol)) {
status = { status:"disallowed", reason:`protocol ${u.protocol}` };
} else {
status = { status:"allowed", url: u.href };
}
} catch (e) {
status = { status:"throws", message: e.message };
}
console.log(JSON.stringify({ input:url, status }));
}
JSRepository: cobaltcore-dev/aurora-dashboard
Length of output: 382
🌐 Web query:
AWS S3 CORS AllowedOrigin wildcard * allowed http://*.example.com documentation
💡 Result:
In AWS S3 CORS configuration, you can use the asterisk () character in the AllowedOrigins element to define allowed origins [1]. There are two primary ways the wildcard is used: 1. Subdomain Wildcards: You can specify a pattern to allow multiple subdomains, such as http://.example.com [1]. According to official AWS documentation, the origin string in the AllowedOrigins element is permitted to contain exactly one asterisk () wildcard character [1]. 2. All Origins: You can specify a single asterisk () as the origin to enable all origins to send cross-origin requests [1][2]. When S3 processes a request, it evaluates the CORS configuration and uses the first rule that matches the incoming request's Origin header [3]. It is important to note that if you use the wildcard (*) as the origin, it may affect the ability to perform credentialed requests, as browsers typically do not allow an Access-Control-Allow-Origin response header of * when credentials (such as cookies or authorization headers) are involved [4].
Citations:
- 1: https://docs.aws.amazon.com/AmazonS3/latest/userguide/ManageCorsUsing.html?icmpid=docs_s3_hp_cors_editor_page
- 2: https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketCors.html
- 3: https://docs.aws.amazon.com/AmazonS3/latest/userguide/cors.html
- 4: https://repost.aws/questions/QUeGIh2VwGTX6qbmhAd-RPag/aws-cors-behavior-for-allowedorigins
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE='packages/aurora/src/client/routes/_auth/projects/$projectId/storage/-components/Ceph/Buckets/TagInput.tsx'
echo "== Relevant file excerpt =="
sed -n '1,200p' "$FILE" | cat -n
echo "== Search urlValidator usages =="
rg -n "urlValidator|AllowedOrigin|CORS|cors|TagInput" packages/aurora/src || true
echo "== JS URL behavior for wildcard candidates =="
node - <<'JS'
const cases = ["*", "http://*.example.com", "https://*.example.com", "http://example.com", "file://*.example.com", "http://a*b.example.com"];
for (const url of cases) {
let status = "allowed";
try {
const u = new URL(url);
status = ["http:", "https:"].includes(u.protocol) ? { status:"allowed", url: u.href } : { status:"disallowed", reason: `protocol ${u.protocol}` };
} catch (e) {
status = { status:"throws", message: e.message };
}
console.log(JSON.stringify({ input: url, status }));
}
JSRepository: cobaltcore-dev/aurora-dashboard
Length of output: 50388
Allow wildcard-subdomain origins in urlValidator.
S3/Ceph CORS accepts origins like http://*.example.com, but new URL(url) rejects any hostname containing *. This form validates AllowedOrigins with urlValidator, so wildcard-subdomain origins cannot be added through the UI even though the CORS backend schema allows string origins. Use a wildcard-safe URL check while still requiring http:/https:.
🤖 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
`@packages/aurora/src/client/routes/_auth/projects/`$projectId/storage/-components/Ceph/Buckets/TagInput.tsx
around lines 97 - 111, The urlValidator currently rejects wildcard-subdomain
origins because URL parsing does not accept * in hostnames. Update urlValidator
to validate http://*.example.com and https://*.example.com forms using
wildcard-safe parsing, while continuing to require only http: or https:
protocols and preserving existing validation results for ordinary URLs.
|
|
||
| // S3 returns CORSRules array or undefined | ||
| const rawCorsRules = response.CORSRules ?? null | ||
|
|
||
| if (!rawCorsRules) { | ||
| return { corsRules: null } | ||
| } | ||
|
|
||
| // Validate and type-check the CORS rules using Zod schema | ||
| const corsRules = rawCorsRules.map((rule) => corsRuleSchema.parse(rule)) | ||
|
|
||
| return { corsRules } | ||
| } catch (error) { | ||
| // NoSuchCORSConfiguration is not an error - it means no CORS config set | ||
| const s3Error = error as { name?: string; Code?: string } | ||
| if (s3Error.name === "NoSuchCORSConfiguration" || s3Error.Code === "NoSuchCORSConfiguration") { | ||
| return { corsRules: null } | ||
| } | ||
|
|
||
| throw mapS3ErrorToTRPCError(error, { | ||
| operation: "get CORS configuration", | ||
| bucket: bucketName, | ||
| }) | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
Does Ceph RGW or AWS S3 PutBucketCors reject MaxAgeSeconds greater than 86400?
💡 Result:
No, Ceph RGW (RADOS Gateway) does not have a hard-coded rejection of MaxAgeSeconds values greater than 86400 (one day) in its PutBucketCors implementation [1]. Technical details: 1. Implementation: In the Ceph RGW codebase, MaxAgeSeconds is processed as an unsigned integer [1]. The function RGWCORSRule::create_rule parses the provided MaxAgeSeconds string using strtoul without imposing an upper-bound check against the value 86400 [1]. 2. Validation: While Ceph RGW validates that the provided input is a valid integer, it does not enforce specific constraints on the magnitude of that integer beyond what the data type supports [2][3][1]. 3. Context: The number 86400 is often associated with the maximum cache time in various web contexts, but it is not a protocol-level limit enforced by S3 specifications or Ceph's current implementation for this parameter [4][5][1]. If you encounter an error when attempting to set a high value, it is likely due to either a malformed XML structure or an invalid integer format (e.g., non-numeric characters) rather than the size of the number itself [2][3].
Citations:
- 1: https://github.com/ceph/ceph/blob/96e268b1/src/rgw/rgw_cors.cc
- 2: https://tracker.ceph.com/issues/26957
- 3: rgw: return err_malformed_xml when MaxAgeSeconds is an invalid integer ceph/ceph#23626
- 4: https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketCors.html
- 5: https://docs.aws.amazon.com/AmazonS3/latest/userguide/ManageCorsUsing.html
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Tracked files matching corsRouter/cors:"
git ls-files | rg '(^|/)corsRouter\.ts$|cors|CORS' || true
echo
echo "Candidate file lines:"
fd -a 'corsRouter\.ts$' . | while read -r f; do
rel="${f#"$PWD"/}"
echo "--- $rel"
wc -l "$rel"
sed -n '1,180p' "$rel" | cat -n
done
echo
echo "Schema references:"
rg -n "corsRuleSchema|MaxAgeSeconds|AllowedMethods|ID|Zod|safeParse|catch" -S .Repository: cobaltcore-dev/aurora-dashboard
Length of output: 50388
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "CORS schema files:"
rg -n "corsRuleSchema|corsSchema|Zod|z\.object|MaxAgeSeconds|AllowedMethods|ID" -S --glob '!node_modules' --glob '!dist' --glob '!build' . | head -200
echo
echo "Exact target file:"
target="$(git ls-files | rg '(^|/)packages/aurora/src/server/Storage/routers/ceph/corsRouter\.ts$' | head -1)"
if [ -n "${target:-}" ]; then
wc -l "$target"
sed -n '1,180p' "$target" | cat -n
fiRepository: cobaltcore-dev/aurora-dashboard
Length of output: 33328
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Locate ceph type definitions:"
fd -a 'ceph\.(ts|tsx|js|jsx)$' . | while read -r f; do
rel="${f#"$PWD"/}"
echo "--- $rel ($(wc -l < "$rel") lines)"
rg -n "corsRuleSchema|corsConfigurationSchema|setCorsInputSchema|getCorsInputSchema|deleteCorsInputSchema|z\.object|MaxAgeSeconds|AllowedMethods" "$rel" || true
done
echo
echo "Search exact schema files in packages/aurora/src/server/types:"
for f in packages/aurora/src/server/types/ceph.ts packages/aurora/src/server/types/ceph/ceph.ts; do
if [ -f "$f" ]; then
echo "--- $f ($(wc -l < "$f") lines)"
nl -ba "$f" | sed -n '1,260p'
fi
doneRepository: cobaltcore-dev/aurora-dashboard
Length of output: 2212
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Relevant ceph schema definitions:"
nl -ba packages/aurora/src/server/Storage/types/ceph.ts | sed -n '488,570p'
echo
echo "Relevant response mapper behavior:"
fd -a 's3ErrorMapper\.(ts|tsx|js|jsx)$' . | while read -r f; do
rel="${f#"$PWD"/}"
echo "--- $rel ($(wc -l < "$rel") lines)"
nl -ba "$rel" | sed -n '1,220p'
doneRepository: cobaltcore-dev/aurora-dashboard
Length of output: 243
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Relevant ceph schema definitions:"
sed -n '488,570p' packages/aurora/src/server/Storage/types/ceph.ts | awk '{printf "%4d %s\n", NR+487, $0}'
echo
echo "Relevant response mapper behavior:"
while read -r f; do
rel="${f#"$PWD"/}"
echo "--- $rel"
sed -n '1,220p' "$f" | awk '{printf "%4d %s\n", NR, $0}'
done < <(git ls-files | rg '(^|/)s3ErrorMapper\.(ts|tsx|js|jsx)$')Repository: cobaltcore-dev/aurora-dashboard
Length of output: 3641
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "List s3ErrorMapper candidates:"
git ls-files | grep -E '(^|/)s3ErrorMapper\.(ts|tsx|js|jsx)$' || true
echo
while IFS= read -r f; do
rel="${f#"$PWD"/}"
echo "--- $rel"
sed -n '1,240p' "$f" | awk '{printf "%4d %s\n", NR, $0}'
done < <(git ls-files | grep -E '(^|/)s3ErrorMapper\.(ts|tsx|js|jsx)$')Repository: cobaltcore-dev/aurora-dashboard
Length of output: 314
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "--- packages/aurora/src/server/Storage/helpers/s3ErrorMapper.ts"
sed -n '1,240p' packages/aurora/src/server/Storage/helpers/s3ErrorMapper.ts | awk '{printf "%4d %s\n", NR, $0}'Repository: cobaltcore-dev/aurora-dashboard
Length of output: 4064
Don’t validate S3 read responses with the write-only CORS schema.
corsRuleSchema enforces write/UI-only constraints such as MaxAgeSeconds ≤ 86400 and AllowedMethods ≤ 5, while Ceph/S3 can store integer MaxAgeSeconds values and longer IDs. A bucket CORS config created outside this UI therefore makes get parse a returned rule and throw; that ZodError is caught as a generic error and mapped to INTERNAL_SERVER_ERROR, breaking view/edit/delete for the existing config. Use a lenient read schema or .safeParse/.catch per rule so reads can still load and delete existing configurations.
🧰 Tools
🪛 ast-grep (0.44.1)
[error] 33-67: Avoid SQL injection
Context: cephProtectedProcedure.input(getCorsInputSchema).query(async ({ ctx, input }): Promise => {
const s3 = ctx.getCephClient()
const { bucketName } = input
try {
const response = await s3.send(
new GetBucketCorsCommand({
Bucket: bucketName,
})
)
// S3 returns CORSRules array or undefined
const rawCorsRules = response.CORSRules ?? null
if (!rawCorsRules) {
return { corsRules: null }
}
// Validate and type-check the CORS rules using Zod schema
const corsRules = rawCorsRules.map((rule) => corsRuleSchema.parse(rule))
return { corsRules }
} catch (error) {
// NoSuchCORSConfiguration is not an error - it means no CORS config set
const s3Error = error as { name?: string; Code?: string }
if (s3Error.name === "NoSuchCORSConfiguration" || s3Error.Code === "NoSuchCORSConfiguration") {
return { corsRules: null }
}
throw mapS3ErrorToTRPCError(error, {
operation: "get CORS configuration",
bucket: bucketName,
})
}
})
Note: [CWE-89] Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection').
(sql-injection-typescript)
🤖 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 `@packages/aurora/src/server/Storage/routers/ceph/corsRouter.ts` around lines
44 - 67, Update the CORS read path around the rawCorsRules mapping so GET
operations do not parse stored rules with the write-only corsRuleSchema. Use a
lenient read schema or safe per-rule parsing that accepts valid S3/Ceph values,
including larger MaxAgeSeconds and longer AllowedMethods collections, while
preserving the existing null and error handling behavior.
Source: Linters/SAST tools
1f7a0d9 to
8f01147
Compare
|
Updated modal flow for CORS Rules modal -> TBC |
872612a to
2c4d996
Compare
Add tRPC router with three endpoints (get/set/delete) for managing CORS configurations on S3/Ceph buckets. Includes Zod schemas for validation, comprehensive test coverage, and S3 error mapping. NoSuchCORSConfiguration is treated as a normal state (returns null), not an error. Signed-off-by: KirylSAP <kiryl.mishchuk@sap.com>
Add modal components for viewing, creating, editing, and deleting CORS rules on Ceph buckets. CorsModal provides tabbed interface (View/Add), CorsRuleForm handles rule editing with TagInput for string arrays (origins, headers), CorsRulesViewer displays existing rules, DeleteCorsModal confirms deletion. All components use React Hook Form with Zod validation. Signed-off-by: KirylSAP <kiryl.mishchuk@sap.com>
Add CORS badge to bucket header, CORS button to header actions, wire modals into BucketModals orchestrator, add toast notifications for CORS operations. Extend useBucketInfo hook to fetch CORS configuration with 5-minute cache and retry: false (no CORS is a normal state). Follows existing patterns from bucket policy and versioning features. Signed-off-by: KirylSAP <kiryl.mishchuk@sap.com>
Add German and English translations for CORS modal titles, form labels, validation messages, toast notifications, and guidance text. Includes descriptions for CORS concepts (origins, methods, headers, MaxAgeSeconds) and wildcard security warnings. Signed-off-by: KirylSAP <kiryl.mishchuk@sap.com>
Signed-off-by: KirylSAP <kiryl.mishchuk@sap.com>
Signed-off-by: KirylSAP <kiryl.mishchuk@sap.com>
2c4d996 to
58f13bf
Compare





Summary
Adds complete CORS (Cross-Origin Resource Sharing) configuration management for Ceph/S3 buckets. Includes a full-stack implementation with tRPC backend endpoints, comprehensive UI with create/edit/delete/view capabilities, and validation for S3 CORS rules.
Changes Made
Backend / tRPC Router
corsRouter.ts: New tRPC router with three endpoints:get: Fetch current CORS configuration (returnsnullfor no config, not an error)set: Create or replace CORS configuration (full replacement, validates rules)delete: Remove CORS configuration (idempotent)corsRouter.test.ts: Comprehensive test suite (512 lines) covering all endpoints, error cases, edge cases, and S3 error mappingceph.ts(types): Added Zod schemas for CORS operations:corsRuleSchema: Validates individual CORS rules (methods, origins, headers, MaxAgeSeconds, ID length)corsConfigurationSchema: Validates full configuration (1-100 rules)s3ErrorMapper.ts: AddedNoSuchCORSConfigurationto error mappingFrontend / UI Components
CorsModal.tsx: Primary modal component with tabbed interface:CorsRulesViewerCorsRuleFormCorsRulesViewer.tsx: Read-only viewer for CORS rules:CorsRuleForm.tsx: Form for creating/editing individual CORS rules:TagInputcomponent for managing string arrays (origins, headers, exposed headers)DeleteCorsModal.tsx: Confirmation modal for deleting entire CORS configurationTagInput.tsx: Reusable component for managing string arrays:BucketModals.tsx: Orchestration component that manages which modal is open (CORS, Policy, Delete, etc.)BucketToastNotifications.tsx: Toast notifications for CORS operations (success/error)Component Updates
BucketHeader.tsx: Added CORS button to bucket detail header actionsBucketHeaderActions.tsx: Wired CORS modal open handleruseBucketInfo.ts: Added CORS data query to consolidated bucket info hook:Test Updates
Related Issues
None
Key Technical Details
CORS Rule Validation
*orhttps://*.example.com)Architecture Pattern
Follows aurora-dashboard's standard tRPC + React Query pattern:
cephProtectedProcedureenforces EC2 credentials, uses AWS SDK v3 S3 commandstrpcReacthooks with React Query for caching/invalidationmapS3ErrorToTRPCErrorgetreturnsnullfor no config,deletesucceeds if already deleted (NoSuchCORSConfiguration is not an error)UX Decisions
PutBucketCorsCommandreplaces entire configuration (S3 behavior)Testing Instructions
pnpm ipnpm run testhttps://example.comChecklist
Summary by CodeRabbit
New Features
Bug Fixes
Tests