diff --git a/.gitignore b/.gitignore index d959c0e524..9e0e4da849 100644 --- a/.gitignore +++ b/.gitignore @@ -151,6 +151,8 @@ node_modules # Persistent data _data/ +/openspec/ +/.gitmodules # AI Instructions (generated by skills/setup.sh from AGENTS.md) CLAUDE.md diff --git a/api/Dockerfile b/api/Dockerfile index 07f69d0b0f..1bcffc479e 100644 --- a/api/Dockerfile +++ b/api/Dockerfile @@ -22,6 +22,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libtool \ libxslt1-dev \ python3-dev \ + git \ && rm -rf /var/lib/apt/lists/* # Install PowerShell diff --git a/api/poetry.lock b/api/poetry.lock index b74417c745..f93e0d21e6 100644 --- a/api/poetry.lock +++ b/api/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.3.4 and should not be changed by hand. [[package]] name = "about-time" @@ -2974,7 +2974,7 @@ files = [ [package.dependencies] autopep8 = "*" Django = ">=4.2" -gprof2dot = ">=2017.09.19" +gprof2dot = ">=2017.9.19" sqlparse = "*" [[package]] @@ -4582,7 +4582,7 @@ files = [ [package.dependencies] attrs = ">=22.2.0" -jsonschema-specifications = ">=2023.03.6" +jsonschema-specifications = ">=2023.3.6" referencing = ">=0.28.4" rpds-py = ">=0.7.1" @@ -4790,7 +4790,7 @@ librabbitmq = ["librabbitmq (>=2.0.0) ; python_version < \"3.11\""] mongodb = ["pymongo (==4.15.3)"] msgpack = ["msgpack (==1.1.2)"] pyro = ["pyro4 (==4.82)"] -qpid = ["qpid-python (==1.36.0-1)", "qpid-tools (==1.36.0-1)"] +qpid = ["qpid-python (==1.36.0.post1)", "qpid-tools (==1.36.0.post1)"] redis = ["redis (>=4.5.2,!=4.5.5,!=5.0.2,<6.5)"] slmq = ["softlayer_messaging (>=1.0.3)"] sqlalchemy = ["sqlalchemy (>=1.4.48,<2.1)"] @@ -4811,7 +4811,7 @@ files = [ ] [package.dependencies] -certifi = ">=14.05.14" +certifi = ">=14.5.14" durationpy = ">=0.7" google-auth = ">=1.0.1" oauthlib = ">=3.2.2" @@ -6964,11 +6964,11 @@ description = "C parser in Python" optional = false python-versions = ">=3.10" groups = ["main", "dev"] +markers = "platform_python_implementation != \"PyPy\" and implementation_name != \"PyPy\"" files = [ {file = "pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992"}, {file = "pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29"}, ] -markers = {main = "implementation_name != \"PyPy\" and platform_python_implementation != \"PyPy\"", dev = "platform_python_implementation != \"PyPy\" and implementation_name != \"PyPy\""} [[package]] name = "pydantic" @@ -7194,7 +7194,7 @@ files = [ ] [package.dependencies] -astroid = ">=3.2.2,<=3.3.0-dev0" +astroid = ">=3.2.2,<=3.3.0.dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} dill = [ {version = ">=0.3.7", markers = "python_version >= \"3.12\""}, @@ -7216,7 +7216,7 @@ description = "The MSALRuntime Python Interop Package" optional = false python-versions = ">=3.6" groups = ["main"] -markers = "(platform_system == \"Windows\" or platform_system == \"Darwin\" or platform_system == \"Linux\") and sys_platform == \"win32\"" +markers = "sys_platform == \"win32\" and (platform_system == \"Windows\" or platform_system == \"Darwin\" or platform_system == \"Linux\")" files = [ {file = "pymsalruntime-0.18.1-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:0c22e2e83faa10de422bbfaacc1bb2887c9025ee8a53f0fc2e4f7db01c4a7b66"}, {file = "pymsalruntime-0.18.1-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:8ce2944a0f944833d047bb121396091e00287e2b6373716106da86ea99abf379"}, @@ -8209,10 +8209,10 @@ files = [ ] [package.dependencies] -botocore = ">=1.37.4,<2.0a.0" +botocore = ">=1.37.4,<2.0a0" [package.extras] -crt = ["botocore[crt] (>=1.37.4,<2.0a.0)"] +crt = ["botocore[crt] (>=1.37.4,<2.0a0)"] [[package]] name = "safety" diff --git a/poetry.lock b/poetry.lock index b9a48f1c3b..06941386e5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1934,6 +1934,7 @@ files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +markers = {dev = "platform_system == \"Windows\" or sys_platform == \"win32\""} [[package]] name = "contextlib2" @@ -3102,7 +3103,7 @@ files = [ [package.dependencies] attrs = ">=22.2.0" -jsonschema-specifications = ">=2023.03.6" +jsonschema-specifications = ">=2023.3.6" referencing = ">=0.28.4" rpds-py = ">=0.7.1" @@ -3182,7 +3183,7 @@ files = [ ] [package.dependencies] -certifi = ">=14.05.14" +certifi = ">=14.5.14" durationpy = ">=0.7" google-auth = ">=1.0.1" oauthlib = ">=3.2.2" @@ -4988,7 +4989,7 @@ files = [ ] [package.dependencies] -astroid = ">=3.3.8,<=3.4.0-dev0" +astroid = ">=3.3.8,<=3.4.0.dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} dill = [ {version = ">=0.2", markers = "python_version < \"3.11\""}, @@ -5834,10 +5835,10 @@ files = [ ] [package.dependencies] -botocore = ">=1.37.4,<2.0a.0" +botocore = ">=1.37.4,<2.0a0" [package.extras] -crt = ["botocore[crt] (>=1.37.4,<2.0a.0)"] +crt = ["botocore[crt] (>=1.37.4,<2.0a0)"] [[package]] name = "safety" diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md index 2555359d15..490c2b7449 100644 --- a/ui/CHANGELOG.md +++ b/ui/CHANGELOG.md @@ -6,17 +6,23 @@ All notable changes to the **Prowler UI** are documented in this file. ### 🔄 Changed +- Redesign compliance page, client-side search for compliance frameworks, compact scan selector trigger, enhanced compliance cards [(#10767)](https://github.com/prowler-cloud/prowler/pull/10767) - Allows tenant owners to expel users from their organizations [(#10787)](https://github.com/prowler-cloud/prowler/pull/10787) - Shared filter dropdowns now support local option search and auto-scroll to the first visible match across table and provider filters - Resources now use batch-applied filters, render metadata JSON with syntax highlighting, simplify metadata/tags tabs, and keep finding-row Learn more links interactive inside the drawer [(#10861)](https://github.com/prowler-cloud/prowler/pull/10861) - -### ❌ Removed - -- Redesign compliance page with a horizontal ThreatScore card (always-visible pillar breakdown + ActionDropdown), client-side search for compliance frameworks, compact scan selector trigger, responsive mobile filters, download-started toasts for CSV/PDF exports, enhanced compliance cards with truncated titles, and Alert-based empty/error states; migrate Progress component from HeroUI to shadcn [(#10767)](https://github.com/prowler-cloud/prowler/pull/10767) +- Shared filter dropdowns now support local option search and auto-scroll to the first visible match across table and provider filters [(#10859)](https://github.com/prowler-cloud/prowler/pull/10859) - Backward-compatibility middleware redirect from `/sign-up?invitation_token=…` to `/invitation/accept?invitation_token=…`; new invitation emails use `/invitation/accept` directly [(#10797)](https://github.com/prowler-cloud/prowler/pull/10797) --- +## [1.24.4] (Prowler UNRELEASED) + +### 🐞 Fixed + +- Provider wizard no longer advances to the Launch Scan step when rotating credentials [(#10851)](https://github.com/prowler-cloud/prowler/pull/10851) + +--- + ## [1.24.2] (Prowler v5.24.2) ### 🐞 Fixed diff --git a/ui/components/providers/wizard/hooks/use-provider-wizard-controller.test.tsx b/ui/components/providers/wizard/hooks/use-provider-wizard-controller.test.tsx index 187c1e0251..9688c3d684 100644 --- a/ui/components/providers/wizard/hooks/use-provider-wizard-controller.test.tsx +++ b/ui/components/providers/wizard/hooks/use-provider-wizard-controller.test.tsx @@ -153,7 +153,7 @@ describe("useProviderWizardController", () => { expect(onOpenChange).not.toHaveBeenCalled(); }); - it("moves to launch step after a successful connection test in update mode", async () => { + it("closes the wizard after a successful connection test in update mode", async () => { // Given const onOpenChange = vi.fn(); const { result } = renderHook(() => @@ -181,9 +181,10 @@ describe("useProviderWizardController", () => { result.current.handleTestSuccess(); }); - // Then - expect(result.current.currentStep).toBe(PROVIDER_WIZARD_STEP.LAUNCH); - expect(onOpenChange).not.toHaveBeenCalled(); + // Then: credential rotation never surfaces the launch/schedule step + expect(onOpenChange).toHaveBeenCalledWith(false); + expect(refreshMock).toHaveBeenCalledTimes(1); + expect(result.current.currentStep).not.toBe(PROVIDER_WIZARD_STEP.LAUNCH); }); it("does not override launch footer config in the controller", () => { diff --git a/ui/components/providers/wizard/hooks/use-provider-wizard-controller.ts b/ui/components/providers/wizard/hooks/use-provider-wizard-controller.ts index 21fce019aa..40644450c2 100644 --- a/ui/components/providers/wizard/hooks/use-provider-wizard-controller.ts +++ b/ui/components/providers/wizard/hooks/use-provider-wizard-controller.ts @@ -197,6 +197,12 @@ export function useProviderWizardController({ }; const handleTestSuccess = () => { + if ( + useProviderWizardStore.getState().mode === PROVIDER_WIZARD_MODE.UPDATE + ) { + handleClose(); + return; + } setCurrentStep(PROVIDER_WIZARD_STEP.LAUNCH); }; @@ -234,6 +240,7 @@ export function useProviderWizardController({ handleTestSuccess, isOrgDirectEntry, isProviderFlow, + mode, modalTitle, openOrganizationsFlow, orgCurrentStep, diff --git a/ui/components/providers/wizard/provider-wizard-modal.tsx b/ui/components/providers/wizard/provider-wizard-modal.tsx index 9157ca74ce..706045a829 100644 --- a/ui/components/providers/wizard/provider-wizard-modal.tsx +++ b/ui/components/providers/wizard/provider-wizard-modal.tsx @@ -10,7 +10,10 @@ import { DialogHeader, DialogTitle } from "@/components/shadcn/dialog"; import { Modal } from "@/components/shadcn/modal"; import { useScrollHint } from "@/hooks/use-scroll-hint"; import { ORG_SETUP_PHASE, ORG_WIZARD_STEP } from "@/types/organizations"; -import { PROVIDER_WIZARD_STEP } from "@/types/provider-wizard"; +import { + PROVIDER_WIZARD_MODE, + PROVIDER_WIZARD_STEP, +} from "@/types/provider-wizard"; import { useProviderWizardController } from "./hooks/use-provider-wizard-controller"; import { @@ -23,7 +26,12 @@ import { WIZARD_FOOTER_ACTION_TYPE } from "./steps/footer-controls"; import { LaunchStep } from "./steps/launch-step"; import { TestConnectionStep } from "./steps/test-connection-step"; import type { OrgWizardInitialData, ProviderWizardInitialData } from "./types"; -import { WizardStepper } from "./wizard-stepper"; +import { PROVIDER_WIZARD_STEPS, WizardStepper } from "./wizard-stepper"; + +const UPDATE_MODE_WIZARD_STEPS = PROVIDER_WIZARD_STEPS.slice( + 0, + PROVIDER_WIZARD_STEP.LAUNCH, +); interface ProviderWizardModalProps { open: boolean; @@ -47,6 +55,7 @@ export function ProviderWizardModal({ handleTestSuccess, isOrgDirectEntry, isProviderFlow, + mode, modalTitle, openOrganizationsFlow, orgCurrentStep, @@ -97,7 +106,14 @@ export function ProviderWizardModal({