Release v2.3.0: ARM64 support + configurable SSL enforcement#699
Release v2.3.0: ARM64 support + configurable SSL enforcement#699aaronlippold wants to merge 192 commits intomasterfrom
Conversation
Signed-off-by: Aaron Lippold <lippold@gmail.com>
…able ## Changes ### Production Configuration - Make config.force_ssl configurable via FORCE_SSL env var (defaults to true) - Make config.assume_ssl respect FORCE_SSL setting (DRY approach) - Both settings now controlled by single environment variable ### Documentation - Update ENVIRONMENT_VARIABLES.md with FORCE_SSL usage - Update .env.production.example with FORCE_SSL documentation - Update docs/getting-started/environment-variables.md with use cases ## Use Cases **Local/Dev Kubernetes (no ingress):** - Set FORCE_SSL=false - Allows HTTP access without SSL redirects - Suitable for Kind, Minikube, development clusters **Production (with ingress + TLS):** - Set FORCE_SSL=true (default) - Enforces HTTPS, secure cookies, HSTS headers - Ingress handles SSL termination ## Benefits - Helm chart compatibility for local development - Maintains security defaults for production - Single configuration point for SSL behavior - Backward compatible (defaults to true) Authored by: Aaron Lippold<lippold@gmail.com>
|
- Add health_check gem (3.1.0) - Add /up endpoint (Rails 8 liveness check) - Add /health_check endpoints (database, ldap, oidc) - Add /status endpoint (application status JSON) - Update all deployment documentation - Add monitoring guide Provides Kubernetes-ready health monitoring with proper liveness, readiness, and startup probe endpoints. Authored by: Aaron Lippold<lippold@gmail.com>
- Add valid_email2 gem for email validation - Production SMTP validation (Discourse pattern) - Validates email format and blocks example.com domains - Validates required SMTP settings when enabled - Fails fast with helpful error messages - Only validates on server start (not rake tasks) - User model blocks disposable email providers - Create membership factory (was missing) - Fix test isolation with Settings.reload! - Add comprehensive test coverage (28 new tests) - Update testing documentation with prerequisites Prevents production email misconfiguration that triggers spam filters. Better than GitLab's approach (no validation). Authored by: Aaron Lippold<lippold@gmail.com>
- Add rails_app_version gem (centralized version management) - VERSION file as single source of truth - Automated release workflow (tag-based) - Phase 1: Validate (VERSION/package.json consistency) - Phase 2: Test (RSpec + RuboCop + Brakeman) - Phase 3: Create draft release (CHANGELOG extraction) - Phase 4: Build Docker (multi-platform amd64+arm64) - Phase 5: Publish release (only if all succeed) - Version bump rake tasks (bump_patch/minor/major, sync, check) - Failure isolation prevents pollution - Rewrite release-process.md with modern workflow Developer experience: rails version:bump_minor # Follow printed instructions git push origin v2.4.0 # GitHub Actions handles everything else Authored by: Aaron Lippold<lippold@gmail.com>
- Update README.md - Update docker-compose files - Remove empty vue3-migration.md - Schema updates from test runs Authored by: Aaron Lippold<lippold@gmail.com>
- Add official Helm chart as recommended deployment method - Link to vulcan-helm repository - Update manual examples to match helm chart tested values: - Image version: v2.3.0 - PostgreSQL: 16-alpine (from 15) - Startup probe initialDelaySeconds: 30 (from 0) - Clarify manual examples are for learning/customization - Helm chart is source of truth for production Ensures Vulcan docs and helm chart stay in sync. Authored by: Aaron Lippold<lippold@gmail.com>
- Add early exit if admin user already exists - Prevents duplicate data on multiple db:seed runs - Follows Rails convention: seeds run once, use db:reset for fresh data - Provides helpful message about db:reset Fixes issue where running bin/setup multiple times created duplicate users and projects. Authored by: Aaron Lippold <lippold@gmail.com> Signed-off-by: Aaron Lippold <lippold@gmail.com>
- Add prometheus_exporter gem for observability - Expose metrics on port 9394 (/metrics endpoint) - Track HTTP requests, database queries, process metrics - Only start prometheus server during Rails server/puma (not rake tasks) - Prevents 'Address already in use' errors during db:prepare - Includes comprehensive metrics tests Metrics available at: - Development: http://localhost:9394/metrics - Production: http://app:9394/metrics - Kubernetes: Scraped by Prometheus Operator Part of v2.3.0 production readiness and monitoring improvements. Authored by: Aaron Lippold <lippold@gmail.com> Signed-off-by: Aaron Lippold <lippold@gmail.com>
- Fix Node.js installation using official binaries (not NodeSource) - Add corporate certificate support via certs/ directory - Expose port 9394 for Prometheus metrics - Multi-platform support (amd64 + arm64) - Update monitoring documentation with Prometheus section These Dockerfiles will be replaced by dockerfile-rails generated version in next commit, but preserving current improvements. Authored by: Aaron Lippold <lippold@gmail.com> Signed-off-by: Aaron Lippold <lippold@gmail.com>
Add dockerfile-rails gem (Rails community standard from Fly.io). This will be used to generate optimized, production-ready Dockerfile following Rails best practices. Replaces custom Dockerfile maintenance with generated approach. Authored by: Aaron Lippold <lippold@gmail.com> Signed-off-by: Aaron Lippold <lippold@gmail.com>
Silences warning about nkf being removed from default gems in Ruby 3.4. Authored by: Aaron Lippold <lippold@gmail.com> Signed-off-by: Aaron Lippold <lippold@gmail.com>
Replace custom Dockerfiles with Rails community standard (dockerfile-rails gem). Key changes: - Single Dockerfile (replaces Dockerfile + Dockerfile.production) - Multi-stage build with jemalloc optimization - config/dockerfile.yml - single source of truth for Docker config - Custom CA certificate support via instruction files - Prometheus port 9394 exposed via deploy instructions - docker-compose.yml for full-stack deployment - bin/docker-entrypoint with db:migrate (not db:prepare) Configuration (config/dockerfile.yml): - PostgreSQL support - jemalloc memory allocator - Build packages: git, gnupg, zlib1g-dev (for fast_excel gem) - Custom instructions for CA certs and Prometheus port Benefits: - Maintainable (regenerate via: rails generate dockerfile --force) - Standard Rails approach (not custom solutions) - Tested on amd64 and arm64 - Works in corporate environments with custom CA Authored by: Aaron Lippold <lippold@gmail.com> Signed-off-by: Aaron Lippold <lippold@gmail.com>
Following Twelve-Factor App principles, all ports now configurable via ENV. New environment variables: - VULCAN_RAILS_PORT (default: 3000, falls back to PORT for compatibility) - VULCAN_PROMETHEUS_PORT (default: 9394) - VULCAN_PROMETHEUS_BIND (default: 0.0.0.0) Changes: - config/initializers/00_environment_config.rb - centralized env config - config/initializers/prometheus.rb - use Vulcan::Config for ports - config/puma.rb - use VULCAN_RAILS_PORT with PORT fallback - config/environments/production.rb - mailer uses VULCAN_APP_URL - Procfile.dev - parameterized ports - ENVIRONMENT_VARIABLES.md - documented all port variables Tested with custom ports (8080, 9095) - all endpoints functional. Authored by: Aaron Lippold <lippold@gmail.com> Signed-off-by: Aaron Lippold <lippold@gmail.com>
Auto-generated schema from migrations. Authored by: Aaron Lippold <lippold@gmail.com> Signed-off-by: Aaron Lippold <lippold@gmail.com>
Add VULCAN_RAILS_PORT, VULCAN_PROMETHEUS_PORT, VULCAN_PROMETHEUS_BIND to .env examples as optional (commented) configuration. Users can now see all available port customization options. Authored by: Aaron Lippold <lippold@gmail.com> Signed-off-by: Aaron Lippold <lippold@gmail.com>
Add support for all CA certificate environment variable standards and corporate proxy configuration. Changes: - Support NODE_EXTRA_CA_CERTS, SSL_CERT_FILE, SSL_CERT_DIR, CURL_CA_BUNDLE, REQUESTS_CA_BUNDLE - Configure npm and yarn cafile for SSL interception - Support HTTP_PROXY/HTTPS_PROXY build args - Works with multiple corporate proxy configurations Note: Docker builds on MITRE VPN may fail due to network policy blocking yarn registry. Build off-VPN or in CI/CD (GitHub Actions has no VPN). Authored by: Aaron Lippold <lippold@gmail.com> Signed-off-by: Aaron Lippold <lippold@gmail.com>
Regenerated after adding comprehensive CA cert and proxy support to instruction files. No functional changes, just updated from templates. Authored by: Aaron Lippold <lippold@gmail.com> Signed-off-by: Aaron Lippold <lippold@gmail.com>
Changes: - Changed rule_update_params from params.expect to params.require().permit() - Rails 8's params.expect was preventing nested arrays from being permitted - Affects checks_attributes, disa_rule_descriptions_attributes, rule_descriptions_attributes - Added comprehensive request specs to prevent regression Impact: - Fixes bug where check text, fix text, and vuln descriptions weren't persisting - Users reported changes reverting after save - now resolved - All 273 existing tests pass + 6 new tests for nested attribute updates Testing: - Added spec/requests/rules_spec.rb with tests for: - Check content updates - Fixtext updates - DISA rule description updates - Status updates - Multi-field updates simulating real frontend behavior Root Cause: params.expect with nested arrays was marking params as permitted: false, causing nested attributes to be filtered out and arrive as nil in the controller. Using params.require().permit() properly handles nested array parameters. Authored by: Aaron Lippold<lippold@gmail.com>
Changes:
- Fixed create_rule_satisfactions to handle satisfied_by lists with or without trailing periods
- Changed from .delete('.') to .sub(/\.\s*\z/, '') to only remove trailing period
- Added comprehensive tests for parser edge cases
Tests Added:
- Parses satisfied_by list with trailing period
- Parses satisfied_by list without trailing period
- Parses satisfied_by list with extra whitespace
- Tests for satisfied_by relationship and status preservation (3 tests)
Impact:
- Spreadsheet imports no longer fail when satisfied_by lists don't end with period
- More robust parsing handles various formatting styles
- Confirms backend status logic is correct (status IS preserved)
All 280 tests passing.
Authored by: Aaron Lippold<lippold@gmail.com>
Problem: When adding a satisfied_by relationship to a control, the UI would not properly update to show fields appropriate for "Applicable - Configurable" status. Fields would disappear or tooltips would show incorrectly. Root Cause: Multiple computed properties and template conditions were checking only rule.status, not considering rule.satisfied_by.length. Since rules with satisfied_by relationships should behave like "Applicable - Configurable" status, these checks were incomplete. Changes: - BasicRuleForm.vue: Updated disaDescriptionFormFields and checkFormFields computed properties to check satisfied_by.length > 0 || status == "Applicable - Configurable" - AdvancedRuleForm.vue: Updated template v-if conditions for disa descriptions, checks, and field visibility warnings - RuleForm.vue: Updated CheckForm v-if condition to include satisfied_by check - CheckForm.vue: Updated tooltips computed property to check satisfied_by Impact: - UI now correctly shows/hides fields when satisfied_by relationships change - Check text, vuln discussion fields properly visible after adding satisfied_by - Tooltips display correctly based on effective status - Fields no longer disappear unexpectedly after nesting controls Note: Backend status logic was already correct (verified with model specs). This fix addresses only the frontend reactivity issues. Future Improvement: Consider adding Vitest/Playwright for Vue component testing to catch these issues. Authored by: Aaron Lippold<lippold@gmail.com>
Setup: - Added Vitest with @vitejs/plugin-vue2 for Vue 2.7 support - Configuration based on HabitRPG/habitica (production Vue 2 + Vitest project) - Test pattern: Test computed properties directly without full component mounting - Avoids complex SFC mounting issues while testing critical logic Dependencies Added: - vitest, @vitest/ui, jsdom, happy-dom - @vitejs/plugin-vue2 (correct Vue 2 plugin) - @vue/test-utils@1.3.6 (Vue 2 version) - @vue/server-renderer (aliased to vue-server-renderer@2.7.16) - postcss-import, postcss-flexbugs-fixes, postcss-preset-env Test Coverage: - BasicRuleForm.spec.js (7 tests, all passing) - Tests checkFormFields computed property with satisfied_by reactivity - Tests disaDescriptionFormFields computed property with satisfied_by reactivity - Validates the Vue reactivity bug fixes from previous commit Scripts Added: - yarn test:unit - Run tests in watch mode - yarn test:unit:ui - Run tests with UI - yarn test:unit:run - Run tests once (CI mode) All 7 tests passing. Tests verify that computed properties correctly check satisfied_by.length > 0 in addition to status checks. Authored by: Aaron Lippold<lippold@gmail.com>
Added Vitest tests for all Vue components modified in reactivity fix: - AdvancedRuleForm.spec.js (6 tests) - CheckForm.spec.js (4 tests) - RuleForm.spec.js (4 tests) Total: 21 frontend tests, all passing Tests verify: - Computed properties react to satisfied_by.length changes - Fields display correctly when satisfied_by relationships exist - Tooltips show appropriate messages based on satisfied_by - Status text returns correct value with satisfied_by All tests validate the bug fixes for status/field visibility issues when adding satisfied_by relationships to controls. Authored by: Aaron Lippold<lippold@gmail.com>
Replaced single-select dropdown with multi-select checkbox list in the "Also Satisfies" modal, allowing users to add multiple satisfied_by relationships at once instead of one-at-a-time. Changes: - Replaced vue-simple-suggest with Bootstrap-Vue b-form-checkbox-group - Added search filter for checkbox list (real-time filtering) - Added scrollable container (400px max-height) for large control lists - Shows selection count in modal - Emits multiple addSatisfied:rule events on submit - Clears selections when modal is hidden UI Improvements: - Modal sized to 'lg' for better visibility - Search box filters checkboxes in real-time (case-insensitive) - Disabled submit button when no selections - Shows "X control(s) selected" counter - "Add X Control(s)" button text updates dynamically Tests Added: - RuleEditorHeader.spec.js (3 tests) - Tests filteredSelectRulesForCheckbox computed property - Validates search filtering logic Impact: Major UX improvement for users managing large SRGs (273 controls). Can now select and add 10+ satisfied_by relationships in one action instead of opening modal 10+ times. All 24 frontend tests + 280 backend tests passing. Authored by: Aaron Lippold<lippold@gmail.com>
Added individual expand/collapse functionality for parent controls in the sidebar "All Controls" list when "Nest Satisfied Controls" is enabled. Changes: - Added expandedParents object to track expand state per parent (rule.id => boolean) - Added chevron-down/chevron-right icon next to parent controls with children - Wrapped nested controls in b-collapse with v-model bound to expandedParents - Added toggleParentExpand() and isParentExpanded() methods - Chevron is clickable with @click.stop to prevent row selection UX Improvements: - When nesting is enabled, parents start COLLAPSED by default - Shows only parent controls initially (e.g., 15 parents instead of 273 total) - Click chevron to expand/collapse individual parent's nested children - Nested controls indented with ml-3 for visual hierarchy - Focus on the core controls that need attention Impact: Major UX improvement for large SRGs. Users can now focus on just the parent controls (15) and expand individual parents as needed, instead of seeing all 273 controls at once. Pattern: Uses standard Bootstrap-Vue b-collapse with v-model, same pattern as RuleSatisfactions component. All 280 backend tests + 24 frontend tests passing. Authored by: Aaron Lippold<lippold@gmail.com>
Implemented rich metrics display on component cards showing primary controls, inherited requirements, and completion progress using Bootstrap-Vue components. Backend Changes: - Added primary_controls_count method (total - nested) - Added rules_summary method returning hash with all metrics - Included in as_json output for frontend consumption - Metrics: primary_count, nested_count, locked, under_review, not_under_review, changes_requested, plus all status breakdowns Frontend Changes: - Added b-list-group showing Primary Controls and Inherited counts - Added b-progress with multi-segment bar (Locked/Review/Draft) - Used proper compliance terminology: "Inherited" for nested requirements - Color-coded: Success (locked), Warning (review), Info (draft) Display Logic: - Shows "223 Primary Controls" + "50 Inherited" when nesting exists - Shows "273 Controls" when no nesting - Progress bar visualizes completion state - Inherited only shown when nested_count > 0 Tests Added: - Backend: 4 tests for parent_rules_count calculation - Frontend: 4 tests for ComponentCard display logic - All 28 frontend + 284 backend tests passing UX Impact: Users can now see at-a-glance: - Total scope (273 requirements) - Work scope (223 primary controls to implement) - Inheritance (50 covered by parents) - Progress (75 locked, 50 under review, etc.) Terminology: "Inherited" matches compliance industry standard for requirements covered by parent/common controls. Authored by: Aaron Lippold<lippold@gmail.com>
Changes to member selection to improve privacy: - Project.available_members now returns scoped results - Component.available_members limited to project members - Added tests for member selection behavior Also updated dependencies: - Updated rack to 3.2.4 - Updated rexml to 3.4.4 All 287 tests passing. Authored by: Aaron Lippold<lippold@gmail.com>
Implemented multiple security improvements based on OWASP best practices and security audit findings. File Upload Validation: - Added validate_spreadsheet_file method to Component model - Validates file extension (xlsx, xls, csv, ods only) - Enforces 100MB file size limit - Prevents malicious file uploads Security Headers: - Added config/initializers/security_headers.rb - X-Frame-Options: SAMEORIGIN (prevent clickjacking) - X-Content-Type-Options: nosniff (prevent MIME sniffing) - X-XSS-Protection: enabled - Referrer-Policy: strict-origin-when-cross-origin - Permissions-Policy: restricts geolocation, camera, microphone Rate Limiting: - Added rack-attack gem - Login attempts: 5 per email per 20 seconds - Login attempts: 20 per IP per minute - Registration: 3 per IP per hour - API requests: 300 per IP per 5 minutes - Safelists localhost and health check endpoints - Returns 429 with rate limit headers Dependency Updates: - Updated Puma 5.6 → 6.6 (Rack 3 compatibility) - Rack 3 required for latest security patches Authorization: - Audited all controllers - authorization present on all actions - RulesController, ComponentsController, ProjectsController all have proper before_action :authorize_* filters Brakeman: Still clean (0 warnings) Bundle Audit: Clean (all CVEs patched) All 287 tests passing. Authored by: Aaron Lippold<lippold@gmail.com>
Added full test coverage for all security improvements to prevent regression. File Upload Validation Tests (4 tests): - Rejects non-spreadsheet files (exe, bat, etc.) - Accepts valid spreadsheet files (csv, xlsx, xls, ods) - Rejects files over 100MB - Accepts files under limit - Uses Rack::Test::UploadedFile with real fixtures Security Headers Tests (6 tests): - Verifies X-Frame-Options header - Verifies X-Content-Type-Options header - Verifies X-XSS-Protection header - Verifies Referrer-Policy header - Verifies Permissions-Policy header - Tests on both public and authenticated endpoints Rate Limiting Tests (9 tests): - Login throttling by email (5 attempts) - Case-insensitive email throttling - Login throttling by IP (20 attempts) - IP isolation (separate limits per IP) - Health check safelisting (/up, /status, /health_check) - General API throttling tracking - Proper test isolation with cache clearing Test Pattern: - Follows Rack::Attack official test patterns - Uses clear_configuration only after(:all) - Clears cache before(:each) for isolation - Tests against actual throttle configuration - Uses unique IPs/emails to avoid test pollution Test Fixtures Added: - spec/fixtures/files/test.csv - spec/fixtures/files/malicious.exe All 306 tests passing (287 backend + 9 rate limiting + 6 headers + 4 file upload). Authored by: Aaron Lippold<lippold@gmail.com>
…tion Implement generic app banner component for top/bottom of pages. Replaces classification-specific banner with flexible system. Changes: - Add AppBanner.vue with Bootstrap color name support - Integrate banner into AuthHeader, Navbar, and AppFooter - Add FooterCopyright component with theme-aware text colors - Rename ClassificationBanner -> AppBanner (more generic) - Configure banner via vulcan.yml and environment variables - Expose banner config to Vue via window.vueAppData Color system: - Bootstrap names: success, warning, danger, primary, etc. - CSS variables: var(--bs-success), var(--custom-color) - Hex codes: #198754, #ffffff - Theme-aware: Adapts to light/dark mode automatically Authored by: Aaron Lippold<lippold@gmail.com>
Add banner settings to admin settings page with live preview. Document environment variables with usage examples. Changes: - Add banner section to admin settings controller API - Display banner config in SettingsPage.vue with color preview - Add VULCAN_BANNER_* environment variables to .env.example - Document banner usage in ENVIRONMENT_VARIABLES.md Configuration options: - VULCAN_BANNER_ENABLED: Show/hide banner - VULCAN_BANNER_TEXT: Banner text - VULCAN_BANNER_BACKGROUND_COLOR: Bootstrap color or hex - VULCAN_BANNER_TEXT_COLOR: Bootstrap color or hex Example use cases: - Development environment indicators - Staging/production markers - Classification levels (UNCLASSIFIED, etc.) - Public release notices Authored by: Aaron Lippold<lippold@gmail.com>
Add resend confirmation, unlock account, and password reset APIs. Display helper links in login form footer. API additions: - resendConfirmation(email): Resend email confirmation - resendUnlock(email): Resend account unlock instructions - validateResetToken(token): Check password reset token validity - resetPassword(token, password, passwordConfirmation): Reset password UI changes: - Add auth helper links below login form - Links to /auth/confirmation and /auth/unlock pages Store/composable updates: - Add methods to auth store for helper actions - Expose helper methods via useAuth composable Authored by: Aaron Lippold<lippold@gmail.com>
Creates a centralized helper that dynamically builds authentication provider configuration for all enabled providers (LDAP, OIDC, OAuth providers like GitHub, Google, GitLab, Azure AD). - Add AuthProvidersHelper module with auth_providers method - Handle both hash and OpenStruct access patterns for provider objects - Provide default titles for LDAP/OIDC when not configured - Include helper in ApplicationController - Expose provider configuration to Vue via window.vueAppData - Add comprehensive RSpec tests (10 tests, all passing) Supports simultaneous multi-provider authentication with proper UX. Authored by: Aaron Lippold<lippold@gmail.com>
Changes auth helper routes (/auth/confirmation, /auth/unlock, /auth/reset-password) to use public#index instead of projects#index, allowing unauthenticated users to access these pages. - Update routes to use PublicController (skips authentication) - Add request specs for all three auth helper routes - Stub Vite helpers in specs to avoid asset compilation in tests - All 3 tests passing Fixes issue where "Resend confirmation" and "Unlock account" links redirected to login page instead of showing the forms. Authored by: Aaron Lippold<lippold@gmail.com>
Adds comprehensive test coverage for authentication helper UI: Component Tests: - EmailConfirmationForm.spec.ts (26 tests) - AccountUnlockForm.spec.ts (26 tests) Page Tests: - EmailConfirmationPage.spec.ts (6 tests) - AccountUnlockPage.spec.ts (6 tests) - PasswordResetEditPage.spec.ts (6 tests) Total: 70 new tests, all passing Tests cover: - Component rendering and structure - Form validation - Form submission with loading states - Mock useAuth composable with getter pattern - Accessibility (labels, ARIA attributes) - Router links and navigation Authored by: Aaron Lippold<lippold@gmail.com>
Migrates remaining authentication pages to Vue 3 SPA architecture: Frontend Changes: - Update App.vue with auth page routes and navigation - Add auth routes to Vue Router (confirmation, unlock, password reset) - Update LoginPage to use router-link for auth helpers - Enhance PasswordInput with show/hide toggle - Update command palette config for auth navigation - Consolidate to single application entrypoint (remove LoginPage.ts) - Remove obsolete ProfilePage.vue Backend Changes: - Update registrations spec to use request spec patterns - Fix routes and authentication flow All auth pages now use Vue Router for seamless SPA navigation. Part of v2.3.0 SPA migration. Authored by: Aaron Lippold<lippold@gmail.com>
Fixed footer being cut off at bottom of viewport by: - Removed footer height constraint in application.scss (was forcing 40px) - Implemented CSS Grid in App.vue (auto 1fr auto pattern) - Updated LoginPage to use h-100 instead of min-vh-100 - Cleaned up outdated flexbox comments in AppFooter Layout changes: - Header: Always visible at top (grid-row: 1) - Main: Scrollable content area (grid-row: 2, overflow-y: auto) - Footer: Always visible at bottom (grid-row: 3) Footer improvements: - Icons-only layout (GitHub + MITRE SAF on right) - Better text contrast (text-white-50) Tests: - Added 6 regression tests (all passing) - SCSS lint test: Prevents footer height constraint - CSS Grid snapshot test: Protects layout solution - Structure tests: Validates HTML elements Authored by: Aaron Lippold<lippold@gmail.com>
Added patterns to hide internal documentation files: - *RECOVERY*.md (recovery files from compact sessions) - *SESSION*.md (session notes and context) - session.md (current session notes) - recovery-prompt.md (recovery prompts) This keeps git status clean by hiding ~120 internal documentation files. Authored by: Aaron Lippold<lippold@gmail.com>
Increased MITRE SAF logo from 1.25rem to 1.5rem for better visual balance with GitHub icon in footer. Authored by: Aaron Lippold<lippold@gmail.com>
Replaced all <a href> links with <router-link> in auth forms for proper SPA navigation without full page refreshes. Route changes: - Added /auth/forgot-password route for ForgotPasswordPage - Updated navigation guard to include forgot-password as public route Component updates: - LoginForm: Use router-link for confirmation/unlock links - LoginForm: Updated forgot password URL to /auth/forgot-password - ForgotPasswordForm: Use router-link for back to sign in - EmailConfirmationForm: Use router-link for back to sign in - PasswordResetForm: Use router-link for back to sign in - AccountUnlockForm: Use router-link for back to sign in Test fixes: - ForgotPasswordForm.spec.ts: Replace global with globalThis (lint fix) Benefits: - No more full page refreshes between auth pages - Faster navigation (stays within SPA) - Prepares for Vue transitions between pages - Better user experience Authored by: Aaron Lippold<lippold@gmail.com>
Added missing Rails route to serve Vue SPA for forgot password page. Without this route, direct navigation or page refresh returns 404. Authored by: Aaron Lippold<lippold@gmail.com>
Changed from standalone app with BApp/AuthHeader/AuthFooter to SPA-integrated page using PageContainer (matches other auth helpers). Also updated title from 'Reset Password' to 'Forgot Password?' to match the link text users clicked. Fixes duplicate header/footer issue. Authored by: Aaron Lippold<lippold@gmail.com>
…e → Composable) ForgotPasswordForm was using inline fetch() instead of following the established architecture pattern. Refactored to use proper layers: API Layer: - Added requestPasswordReset() in auth.api.ts - Added comprehensive tests (7 test cases, all passing) Store Layer: - Added requestPasswordReset() action in auth.store.ts - Follows withAsyncAction pattern for error handling Composable Layer: - Exposed requestPasswordReset() in useAuth composable - Handles toast notifications for success/error states Component Layer: - Refactored ForgotPasswordForm to use useAuth() composable - Simplified from 46 lines to 21 lines - Added proper error handling with try/catch - Updated tests to mock composable instead of fetch (14 tests, all passing) This brings ForgotPasswordForm in line with other auth forms (EmailConfirmationForm, AccountUnlockForm, PasswordResetForm). Tests: 25 API tests + 14 component tests = 39 tests passing Authored by: Aaron Lippold<lippold@gmail.com>
Implemented app-wide page transition system with a simple, balanced approach: CSS (application.scss): - Added .fade-enter-active/.fade-leave-active (200ms opacity transition) - GPU-accelerated (opacity only, no layout thrashing) - Respects prefers-reduced-motion (transitions to 0.01ms for accessibility) Vue (App.vue): - Wrapped RouterView with <Transition name="fade" mode="out-in"> - Added :key="route.path" to ErrorBoundary for proper remounting - Works seamlessly with existing ErrorBoundary and Suspense Design decisions: - Uniform transition everywhere (not route-aware) - 200ms duration (balanced - not jarring, not sluggish) - Simple implementation (15 lines total) - Easy to extend later if needed Benefits: - Smooth navigation throughout the app - Accessible (reduced motion support) - Performant (CSS-only, GPU-accelerated) - Maintainable (single source of truth) Tests: 6 App.vue tests passing Authored by: Aaron Lippold<lippold@gmail.com>
The Transition wrapper outside ErrorBoundary/Suspense was causing pages to disappear during navigation. Moving it inside Suspense and applying :key to the component directly fixes the issue. Authored by: Aaron Lippold<lippold@gmail.com>
Transition with mode='out-in' causes blank pages during navigation. Reverting to no transitions for stability. Authored by: Aaron Lippold<lippold@gmail.com>
Backend: - Add consent_banner configuration to vulcan.default.yml - Create Api::SettingsController#consent_banner endpoint - Add /api/settings/consent_banner route (public, no auth) - 5 request specs passing Frontend: - Create settings.api.ts with fetchConsentBanner() - Create settings.store.ts with Pinia store - Create useConsentBanner composable with localStorage tracking - 27 frontend tests passing (6 API + 10 store + 11 composable) Architecture: API → Store → Composable → Component (complete except component) Next: ConsentModal component with markdown rendering Authored by: Aaron Lippold<lippold@gmail.com>
Component: - Created ConsentModal.vue with markdown rendering (marked + DOMPurify) - Uses Bootstrap 5 modal with backdrop="static" (non-dismissible) - Blurred backdrop via CSS (backdrop-filter: blur(8px)) - XSS protection with DOMPurify sanitization - 8 component tests passing Integration: - Added to App.vue before authentication - Fetches banner config on mount (public endpoint) - Shows modal when enabled and not acknowledged - Blocks access until user clicks "I Agree" - Exported useConsentBanner from composables index Tests: 40 total passing (35 frontend + 5 backend) - API layer: 6 tests - Store layer: 10 tests - Composable layer: 11 tests - Component layer: 8 tests - Backend API: 5 tests Architecture complete: API → Store → Composable → Component → App Authored by: Aaron Lippold<lippold@gmail.com>
- Added VULCAN_CONSENT_BANNER_ENABLED to .env.example - Added VULCAN_CONSENT_BANNER_VERSION to .env.example - Added VULCAN_CONSENT_BANNER_CONTENT to .env.example - Added comprehensive consent banner section to ENVIRONMENT_VARIABLES.md - Includes markdown formatting guide and version management examples - Documents default content, custom content examples, and DoD warning banner Authored by: Aaron Lippold<lippold@gmail.com>
Refactored banner configuration for consistency and added consolidated settings API endpoint following 12-factor principles. Config Changes: - Renamed banner → banner_app for consistent naming - Renamed consent_banner → banner_consent for grouping - ENV override for VULCAN_CONSENT_BANNER_CONTENT in controller layer - Added vite.json configuration API Changes: - Added GET /api/settings consolidated endpoint (all banners) - Preserved GET /api/settings/consent_banner legacy endpoint - Added ui section to /status endpoint for k8s/ops visibility - Updated admin settings controller with nested banners structure Frontend Changes: - Updated settings.api.ts with new interfaces (IAppBanner, ISettings) - Updated App.vue to use Settings.banner_app - Updated ConsentModal.vue props for title and titleAlign - Added Login2.vue experimental login page Tests: - Added 8 backend tests for new /api/settings endpoint - Updated all consent_banner mocks to banner_consent - All tests passing (8 backend, 1348 frontend) Documentation: - Updated docs/getting-started/configuration.md with banner details - Simplified ENVIRONMENT_VARIABLES.md (tables + links) - Updated .env.example with version tracking explanation Benefits: - 12-factor compliant (ENV overrides work for k8s) - Consistent naming (banner_* prefix groups all banners) - Single API call for all UI settings (less HTTP overhead) - Ops visibility in status endpoint Authored by: Aaron Lippold<lippold@gmail.com>
…ord resets, unlocks) Added Vue 3 SPA pages and Rails API endpoints for Devise auth workflows. All features fully tested with 9 passing backend tests. Backend: - PublicController for unauthenticated landing page - Users::ConfirmationsController (JSON API for email confirmation) - Users::PasswordsController (JSON API for password resets) - Users::UnlocksController (JSON API for account unlocks) Frontend: - AccountUnlockPage.vue (request account unlock) - EmailConfirmationPage.vue (resend confirmation email) - PasswordResetEditPage.vue (set new password with token) Utils: - ident-parser.ts utility for parsing identifiers - Full test coverage (9 backend tests passing) Part of v2.3.0 auth migration to Vue 3 SPA architecture. Authored by: Aaron Lippold<lippold@gmail.com>
Added comprehensive user profile management page and Taskfile.yml for task automation. Frontend: - AccountSettingsPage.vue (338 lines) - Profile editing (name, email, Slack ID) - Password change with current password validation - Account deletion with confirmation - OAuth user detection (read-only email for OAuth users) - Uses useProfile composable for state management - Toast notifications for all actions Build Tools: - Taskfile.yml - Task runner configuration - Setup, installation, CLI build tasks - Version and commit tracking - Alternative to Makefile with modern YAML syntax Part of v2.3.0 user management migration. Authored by: Aaron Lippold<lippold@gmail.com>
| name: Validate Release | ||
| runs-on: ubuntu-24.04 | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Validate tag format | ||
| run: | | ||
| TAG="${{ github.ref_name }}" | ||
| if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | ||
| echo "❌ Invalid tag format: $TAG" | ||
| echo "Expected format: v2.3.0" | ||
| exit 1 | ||
| fi | ||
| echo "✅ Valid tag: $TAG" | ||
|
|
||
| - name: Extract version from tag | ||
| id: version | ||
| run: | | ||
| VERSION="${{ github.ref_name }}" | ||
| VERSION_NUMBER="${VERSION#v}" # Remove 'v' prefix | ||
| echo "VERSION=$VERSION_NUMBER" >> $GITHUB_OUTPUT | ||
| echo "TAG=$VERSION" >> $GITHUB_OUTPUT | ||
|
|
||
| - name: Setup Ruby | ||
| uses: ruby/setup-ruby@v1 | ||
| with: | ||
| ruby-version: '3.4.7' | ||
| bundler-cache: true | ||
|
|
||
| - name: Check version consistency | ||
| run: | | ||
| # Read version from VERSION file | ||
| FILE_VERSION=$(cat VERSION | tr -d '\n') | ||
| TAG_VERSION="${{ steps.version.outputs.VERSION }}" | ||
|
|
||
| if [[ "$FILE_VERSION" != "$TAG_VERSION" ]]; then | ||
| echo "❌ Version mismatch!" | ||
| echo " Tag version: $TAG_VERSION" | ||
| echo " VERSION file: $FILE_VERSION" | ||
| echo "" | ||
| echo "Please update VERSION file to match the tag:" | ||
| echo " echo '$TAG_VERSION' > VERSION" | ||
| echo " bundle exec rails version:sync" | ||
| echo " git add VERSION package.json" | ||
| echo " git commit --amend --no-edit" | ||
| echo " git tag -f ${{ github.ref_name }}" | ||
| echo " git push -f origin ${{ github.ref_name }}" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Also check package.json is synced | ||
| PACKAGE_VERSION=$(cat package.json | jq -r '.version') | ||
| if [[ "$PACKAGE_VERSION" != "$TAG_VERSION" ]]; then | ||
| echo "❌ package.json not synced!" | ||
| echo " Tag version: $TAG_VERSION" | ||
| echo " package.json: $PACKAGE_VERSION" | ||
| echo "" | ||
| echo "Run: bundle exec rails version:sync" | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "✅ All versions match: $TAG_VERSION" | ||
|
|
||
| test: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 months ago
To fix this, explicitly define minimal GITHUB_TOKEN permissions for jobs that only need to read repository contents. The validate and test jobs simply check out code, run Ruby/Node setup, and execute tests and static analysis; they do not write to GitHub or modify releases. Therefore, adding permissions: contents: read to these jobs is the least-privilege fix that preserves all existing behavior.
Concretely:
- In
.github/workflows/release.yml, underjobs.validate(just belowruns-on: ubuntu-24.04), add:permissions: contents: read
- In the same file, under
jobs.test(just belowneeds: validate), add:permissions: contents: read
No other changes, imports, or new definitions are required. The publish-release job already has permissions: contents: write and should be left as-is.
| @@ -9,6 +9,8 @@ | ||
| validate: | ||
| name: Validate Release | ||
| runs-on: ubuntu-24.04 | ||
| permissions: | ||
| contents: read | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
| @@ -75,6 +77,8 @@ | ||
| name: Run Test Suite | ||
| runs-on: ubuntu-24.04 | ||
| needs: validate | ||
| permissions: | ||
| contents: read | ||
|
|
||
| services: | ||
| postgres: |
| name: Run Test Suite | ||
| runs-on: ubuntu-24.04 | ||
| needs: validate | ||
|
|
||
| services: | ||
| postgres: | ||
| image: postgres:16-alpine | ||
| env: | ||
| POSTGRES_USER: postgres | ||
| POSTGRES_PASSWORD: postgres | ||
| POSTGRES_DB: vulcan_vue_test | ||
| options: >- | ||
| --health-cmd pg_isready | ||
| --health-interval 10s | ||
| --health-timeout 5s | ||
| --health-retries 5 | ||
| ports: | ||
| - 5432:5432 | ||
|
|
||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Setup Ruby | ||
| uses: ruby/setup-ruby@v1 | ||
| with: | ||
| ruby-version: '3.4.7' | ||
| bundler-cache: true | ||
|
|
||
| - name: Setup Node | ||
| uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: '24' | ||
|
|
||
| - uses: pnpm/action-setup@v4 | ||
| with: | ||
| version: 10 | ||
|
|
||
| - name: Install dependencies | ||
| run: | | ||
| bundle install | ||
| pnpm install | ||
|
|
||
| - name: Setup database | ||
| env: | ||
| RAILS_ENV: test | ||
| DATABASE_URL: postgresql://postgres:postgres@localhost:5432/vulcan_vue_test | ||
| run: | | ||
| bundle exec rails db:create | ||
| bundle exec rails db:migrate | ||
|
|
||
| - name: Run frontend tests | ||
| run: pnpm vitest run | ||
|
|
||
| - name: Run backend tests | ||
| env: | ||
| RAILS_ENV: test | ||
| DATABASE_URL: postgresql://postgres:postgres@localhost:5432/vulcan_vue_test | ||
| run: bundle exec parallel_rspec spec/ | ||
|
|
||
| - name: Run RuboCop | ||
| run: bundle exec rubocop | ||
|
|
||
| - name: Run Brakeman security scan | ||
| run: bundle exec brakeman --no-pager | ||
|
|
||
| create-draft-release: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 months ago
To fix the problem, add an explicit permissions block to the test job that grants only the minimal required scope. Since test just checks out the repository and runs tests, contents: read is sufficient. This prevents the job from inheriting potentially broader default token permissions while preserving all current functionality.
Concretely:
- Edit
.github/workflows/release.yml. - Under the
testjob (the one withname: Run Test Suiteon line 75), insert:
permissions:
contents: readbetween runs-on: ubuntu-24.04 and needs: validate. No other jobs need changes: create-draft-release already has permissions: contents: write, and validate does not appear to require write access (you could optionally also add contents: read there, but CodeQL’s reported issue is about the test job, so we’ll focus on that). No imports or external dependencies are required for this change.
| @@ -74,6 +74,8 @@ | ||
| test: | ||
| name: Run Test Suite | ||
| runs-on: ubuntu-24.04 | ||
| permissions: | ||
| contents: read | ||
| needs: validate | ||
|
|
||
| services: |
| name: Build and Push Docker Images | ||
| runs-on: ubuntu-24.04 | ||
| needs: [validate, test, create-draft-release] | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Set up Docker Buildx | ||
| uses: docker/setup-buildx-action@v3 | ||
|
|
||
| - name: Login to DockerHub | ||
| uses: docker/login-action@v3 | ||
| with: | ||
| username: ${{ secrets.DOCKERHUB_USERNAME }} | ||
| password: ${{ secrets.DOCKERHUB_TOKEN }} | ||
|
|
||
| - name: Extract version from tag | ||
| id: version | ||
| run: | | ||
| VERSION="${{ github.ref_name }}" | ||
| echo "TAG=$VERSION" >> $GITHUB_OUTPUT | ||
|
|
||
| - name: Build and push multi-platform images | ||
| uses: docker/build-push-action@v6 | ||
| with: | ||
| context: . | ||
| file: Dockerfile | ||
| target: production | ||
| push: true | ||
| platforms: linux/amd64,linux/arm64 | ||
| tags: | | ||
| mitre/vulcan:${{ steps.version.outputs.TAG }} | ||
| mitre/vulcan:latest | ||
| cache-from: type=gha | ||
| cache-to: type=gha,mode=max | ||
|
|
||
| - name: Update Docker Hub description | ||
| uses: peter-evans/dockerhub-description@v4 | ||
| with: | ||
| username: ${{ secrets.DOCKERHUB_USERNAME }} | ||
| password: ${{ secrets.DOCKERHUB_TOKEN }} | ||
| repository: mitre/vulcan | ||
| short-description: "STIG-ready security guidance documentation platform" | ||
| readme-filepath: ./README.md | ||
|
|
||
| publish-release: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 months ago
To fix the problem, explicitly restrict the GITHUB_TOKEN permissions for the build-docker job by adding a permissions block that grants only read access to repository contents. This ensures the job does not inherit potentially broader repository defaults (such as contents: write), satisfying the least-privilege recommendation and the CodeQL rule.
Concretely, in .github/workflows/release.yml, within the build-docker job definition (lines around 190–195), add:
permissions:
contents: readjust under needs: [validate, test, create-draft-release] (or directly under runs-on:—order among job-level keys does not matter in YAML). No additional imports or methods are required, and no changes are needed to any steps in the job. This will keep existing functionality intact because the job only needs to check out code and read README.md, which are compatible with contents: read.
| @@ -191,6 +191,8 @@ | ||
| name: Build and Push Docker Images | ||
| runs-on: ubuntu-24.04 | ||
| needs: [validate, test, create-draft-release] | ||
| permissions: | ||
| contents: read | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 |
| project_ids = current_user.available_projects.pluck(:id) | ||
|
|
||
| Component.where(project_id: project_ids) | ||
| .where(*build_ilike_conditions(%w[name prefix])) |
Check failure
Code scanning / CodeQL
SQL query built from user-controlled sources High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 3 months ago
In general, the safest way to fix SQL injection risks in Rails is to avoid manually constructing SQL strings and instead rely on ActiveRecord’s parameterization mechanisms: hashes, arrays with placeholders, or AREL predicates. We should ensure that user-supplied data is only ever used as bound parameters, and never interpolated directly into the query string.
In this case, the primary concern is build_ilike_conditions, which returns a ["sql with ? placeholders", *values] array that is splatted into where. Although the values are safe, the pattern of manually building SQL strings is what triggers the CodeQL alert. The best fix without changing functionality is to refactor build_ilike_conditions so that it no longer returns a raw SQL string, but instead constructs an Arel::Nodes::Node condition tree; we can then pass that node directly to where, which is fully parameterized by Rails/AREL. We keep the existing behavior—OR-ing across both terms and columns, and using %term% ILIKE matching—while letting AREL handle bindings.
Concretely, in app/controllers/api/search_controller.rb, we will:
- Replace the current
build_ilike_conditionsimplementation with one that:- Returns an
Arel::Nodes::Nodeinstead of[sql, *values]. - Uses
arel_table[col].matches("%#{term}%", nil, true)(ormatcheswithArel::Nodes::NamedFunction.new('LOWER', ...)if needed), combined with.oracross columns and terms.
- Returns an
- Update the two call sites:
current_user.available_projects.where(*build_ilike_conditions(%w[name description]))→...where(build_ilike_conditions(Project, %w[name description]))Component.where(project_id: project_ids).where(*build_ilike_conditions(%w[name prefix]))→...where(build_ilike_conditions(Component, %w[name prefix]))
- Change the
build_ilike_conditionsmethod signature to accept the model class, e.g.def build_ilike_conditions(model_class, columns)and usemodel_class.arel_tableto build column references.
No new imports are needed; AREL is available as part of ActiveRecord. Functionality will remain the same: it still performs an OR across all columns and all search terms, but in a way that is clearly parameterized and friendlier to static analysis.
| @@ -49,7 +49,7 @@ | ||
| return [] unless current_user | ||
|
|
||
| current_user.available_projects | ||
| .where(*build_ilike_conditions(%w[name description])) | ||
| .where(build_ilike_conditions(Project, %w[name description])) | ||
| .limit(limit) | ||
| .map do |project| | ||
| { | ||
| @@ -68,7 +68,7 @@ | ||
| project_ids = current_user.available_projects.pluck(:id) | ||
|
|
||
| Component.where(project_id: project_ids) | ||
| .where(*build_ilike_conditions(%w[name prefix])) | ||
| .where(build_ilike_conditions(Component, %w[name prefix])) | ||
| .includes(:project) | ||
| .limit(limit) | ||
| .map do |component| | ||
| @@ -221,18 +221,33 @@ | ||
| # Build ILIKE conditions for multiple search terms across multiple columns | ||
| # Returns array suitable for .where(*result) | ||
| # | ||
| def build_ilike_conditions(columns) | ||
| conditions = [] | ||
| values = [] | ||
| def build_ilike_conditions(model_class, columns) | ||
| table = model_class.arel_table | ||
|
|
||
| # Build an OR condition across all search terms and columns using AREL, | ||
| # so that all user input is passed as bound parameters. | ||
| combined_condition = nil | ||
|
|
||
| @search_terms.each do |term| | ||
| column_conditions = columns.map { |col| "#{col} ILIKE ?" }.join(' OR ') | ||
| conditions << "(#{column_conditions})" | ||
| # Add the term value for each column | ||
| columns.size.times { values << "%#{term}%" } | ||
| next if term.blank? | ||
|
|
||
| term_pattern = "%#{term}%" | ||
|
|
||
| # Build (col1 ILIKE ? OR col2 ILIKE ? ...) for this term | ||
| term_condition = columns.map do |col| | ||
| # Using matches with case-insensitive collation via ILIKE | ||
| table[col].matches(term_pattern) | ||
| end.reduce { |acc, cond| acc.or(cond) } | ||
|
|
||
| combined_condition = if combined_condition | ||
| combined_condition.or(term_condition) | ||
| else | ||
| term_condition | ||
| end | ||
| end | ||
|
|
||
| [conditions.join(' OR ')] + values | ||
| # If there are no search terms, return a no-op condition | ||
| combined_condition || Arel::Nodes::SqlLiteral.new('1=1') | ||
| end | ||
|
|
||
| ## |
| def search_stig_documents(limit) | ||
| return [] unless current_user | ||
|
|
||
| Stig.where(*build_ilike_conditions(%w[name title stig_id])) |
Check failure
Code scanning / CodeQL
SQL query built from user-controlled sources High
Copilot Autofix
AI 3 months ago
Copilot could not generate an autofix suggestion
Copilot could not generate an autofix suggestion for this alert. Try pushing a new commit or if the problem persists contact support.
| def search_srg_documents(limit) | ||
| return [] unless current_user | ||
|
|
||
| SecurityRequirementsGuide.where(*build_ilike_conditions(%w[name title srg_id])) |
Check failure
Code scanning / CodeQL
SQL query built from user-controlled sources High
Copilot Autofix
AI 3 months ago
Copilot could not generate an autofix suggestion
Copilot could not generate an autofix suggestion for this alert. Try pushing a new commit or if the problem persists contact support.
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 25086139 | Triggered | Generic Password | 5d5ca50 | app/javascript/components/auth/tests/PasswordInput.spec.ts | View secret |
| 23525922 | Triggered | Generic Password | e32a867 | cli/cmd/setup_test.go | View secret |
| 23525923 | Triggered | Generic Password | f5ac2e3 | app/javascript/composables/tests/useProfile.spec.ts | View secret |
| 23525924 | Triggered | Generic Password | bb0a44e | docker-compose.dev.yml | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secrets safely. Learn here the best practices.
- Revoke and rotate these secrets.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
Generated by bundler for vite_rails gem. Required for Rails + Vite integration and setup scripts. Fixes setup failure when bin/vite is missing after fresh checkout. Authored by: Aaron Lippold<lippold@gmail.com>
Authored by: Aaron Lippold<lippold@gmail.com>
Updated all consent banner tests to include new title and titleAlign configuration properties added in Session 131-132. Authored by: Aaron Lippold<lippold@gmail.com>
|







Summary
This release adds ARM64/Apple Silicon support and makes SSL enforcement configurable for flexible Kubernetes deployments.
Changes
Multi-Platform Docker Builds
platforms: linux/amd64,linux/arm64in push-to-docker.ymlConfigurable SSL Enforcement
FORCE_SSLenvironment variable supportconfig.force_sslrespectFORCE_SSLsettingconfig.assume_sslrespectFORCE_SSLsetting (DRY approach)Use Cases
Local/Development Kubernetes:
Production (with Ingress + TLS):
FORCE_SSL=true # DefaultTesting
Compatibility
Documentation Updated
Authored by: Aaron Lippoldlippold@gmail.com