* [dev] disable npm lifecycle scripts and npx
* Add npm-tools
* update npm-tools
* dev/image/Dockerfile
* update
Co-authored-by: Ona <no-reply@ona.com>
* Bump leeay version to 0.10.6
Co-authored-by: Ona <no-reply@ona.com>
* Fix npx removal to also delete the target script
The symlink at /root/.nvm/.../bin/npx points to npx-cli.js.
Remove both to ensure npx is fully disabled.
Co-authored-by: Ona <no-reply@ona.com>
* Remove gce-github-runner usage from all workflows
Replace self-hosted GCE runner pattern with GitHub-hosted ubuntu-latest runners across all workflows. This removes the three-phase pattern (create-runner, use-runner, delete-runner) and simplifies workflow execution.
Changes:
- Remove create-runner and delete-runner jobs from all workflows
- Replace runs-on: ${{ needs.create-runner.outputs.label }} with runs-on: ubuntu-latest
- Remove create-runner from job dependencies
- Preserve all other job dependencies and concurrency controls
Affected workflows:
- build.yml (8 jobs)
- workspace-integration-tests.yml (4 jobs)
- ide-integration-tests.yml (4 jobs)
- preview-env-check-regressions.yml (4 jobs)
- preview-env-gc.yml (2 jobs)
- jetbrains-auto-update-template.yml (1 job)
- jetbrains-integration-test.yml (1 job)
- code-nightly.yml (1 job)
- preview-env-delete.yml (1 job)
Co-authored-by: Ona <no-reply@ona.com>
* [dev] use ubuntu-latest-16-cores for builds
* Fix container permissions for GitHub-hosted runners
Add 'options: --user root' to all container configurations to resolve EACCES permission errors when GitHub Actions tries to write to internal directories.
GitHub-hosted runners require containers to run as root to allow the Actions runtime to write to /__w/_temp/_runner_file_commands/ and other internal paths.
Affected workflows:
- build.yml (3 container jobs)
- workspace-integration-tests.yml (2 container jobs)
- ide-integration-tests.yml (2 container jobs)
- preview-env-check-regressions.yml (1 container job)
- preview-env-gc.yml (1 container job)
- jetbrains-auto-update-template.yml (1 container job)
- jetbrains-integration-test.yml (1 container job)
- code-nightly.yml (1 container job)
Co-authored-by: Ona <no-reply@ona.com>
* Fix dev/image build by adding leeway dependency for npm-tools
Create leeway generic build for dev/npm-tools and use it as a dependency in dev/image:docker build. This resolves the build error where npm-tools files were not accessible during Docker build.
Changes:
- Add dev/npm-tools/BUILD.yaml with generic package containing package.json and package-lock.json
- Add dev/npm-tools:pkg as dependency in dev/image/BUILD.yaml
- Update Dockerfile to use COPY from leeway dependency path (dev-npm-tools--pkg/)
This follows the established pattern used in other builds like install/installer where dependencies are copied from leeway-generated paths.
Co-authored-by: Ona <no-reply@ona.com>
* Fix npm-tools installation permissions in dev/image
Add chown command to fix EACCES permission error when installing npm-tools. The COPY command creates files owned by root, but npm ci runs as gitpod user and needs write access to create node_modules.
Changes:
- Add 'sudo chown -R gitpod:gitpod /opt/npm-tools' before npm ci
- This ensures the gitpod user can write to /opt/npm-tools/node_modules/
Error fixed:
npm error code EACCES
npm error syscall mkdir
npm error path /opt/npm-tools/node_modules
npm error errno -13
Co-authored-by: Ona <no-reply@ona.com>
* [dev] Split builds into branch and main
Co-authored-by: Ona <no-reply@ona.com>
---------
Co-authored-by: Cornelius Ludmann <cornelius@ona.com>
Co-authored-by: Ona <no-reply@ona.com>
Co-authored-by: Gero Posmyk-Leinemann <gero@gitpod.io>
Block new user signups when Classic PAYG sunset is enabled:
- Add isUserSignupBlockedBySunset() function in featureflags.ts
- Checks if sunset is enabled for the installation
- Exempts dedicated installations
- Blocks all signups (new users don't have orgs/roles yet)
- Add signup blocking in generic-auth-provider.ts callback
- Check before createNewUser() is called
- Redirect blocked signups to https://app.ona.com/login
- Log blocked signup attempts
This complements the existing login and workspace operation blocks
from CLC-2032, closing the signup path that was previously unblocked.
Co-authored-by: Ona <no-reply@ona.com>
The original sunset implementation only added checks to the new gRPC API
(WorkspaceServiceAPI) but missed the legacy websocket API (GitpodServerImpl).
This allowed users to bypass the sunset blocking through:
- Gitpod CLI/Local App (uses experimental/v1 API)
- JetBrains Gateway (uses websocket API directly)
- Public API with Personal Access Tokens
- Dashboard when feature flag is disabled
This fix adds the sunset check to both startWorkspace() and createWorkspace()
methods in GitpodServerImpl, using the same isWorkspaceStartBlockedBySunset()
function that's already used in WorkspaceServiceAPI.
The check:
- Blocks installation-owned users (no organizationId)
- Blocks users in non-exempted organizations
- Exempts dedicated installations
- Exempts organizations in the exemptedOrganizations list
Co-authored-by: Ona <no-reply@ona.com>
* [CLC-2032] Block login and workspace operations for Classic PAYG sunset
Implement feature flag-based blocking for Gitpod Classic PAYG users:
Backend:
- Add utility functions to check if user is blocked by sunset
- Block login attempts in /login route handler, redirect to app.ona.com
- Block workspace creation and start operations in workspace-service-api
- Exempt users with roles/permissions and users in exempted organizations
Frontend:
- Update login page to show 'Login with Ona' button when sunset is enabled
- Keep SSO login form visible for exempted organizations
- Hide sunset notice banner when flag is enabled
- Update heading to 'Gitpod Classic has sunset'
Feature flag: classic_payg_sunset_enabled (JSON with enabled boolean and exemptedOrganizations array)
Co-authored-by: Ona <no-reply@ona.com>
* Add oldLogin parameter to show full login UI for exempted orgs
When sunset is enabled on gitpod.io, users now see a simplified UI:
- 'Continue with Ona' button (default)
- Link to show all login options (?oldLogin=true)
With ?oldLogin=true parameter:
- Shows all OAuth provider buttons
- Shows SSO login form
- Full functionality for exempted organizations
The link preserves returnToPath parameter if present.
Co-authored-by: Ona <no-reply@ona.com>
* Refactor backend sunset checks into separate functions
Split sunset blocking logic into two functions:
- isUserLoginBlockedBySunset: checks roles/permissions exemption for login
- isWorkspaceStartBlockedBySunset: checks org-level exemption for workspace ops
Move ClassicPaygSunsetConfig interface to gitpod-protocol for reusability.
Pass organizationId explicitly to workspace blocking checks.
Co-authored-by: Ona <no-reply@ona.com>
* Use typed ClassicPaygSunsetConfig in frontend feature flag
Import ClassicPaygSunsetConfig type from gitpod-protocol and use it
as the default value for classic_payg_sunset_enabled feature flag.
This leverages TypeScript's generic type inference in useFeatureFlag:
- useFeatureFlag<K extends keyof FeatureFlags> returns FeatureFlags[K]
- For classic_payg_sunset_enabled, it now returns ClassicPaygSunsetConfig
- Other flags continue to return their respective types (boolean, string, etc.)
Updated Login.tsx to access .enabled property with type guard to handle
the union type (ClassicPaygSunsetConfig | boolean) during loading state.
This ensures type safety and consistency between frontend and backend.
Co-authored-by: Ona <no-reply@ona.com>
* Parse JSON string for classic_payg_sunset_enabled feature flag
ConfigCat text flags return strings, so we need to parse JSON on both
frontend and backend.
Backend (featureflags.ts):
- Send JSON.stringify(defaultConfig) to ConfigCat
- Parse returned string with JSON.parse()
- Handle errors gracefully with fallback to default
Frontend (featureflag-query.ts):
- Add parseFeatureFlagValue() helper for JSON flags
- Send stringified default for classic_payg_sunset_enabled
- Parse returned string value
- Maintain type safety with generic return types
This allows ConfigCat to store the flag as text while maintaining
the typed object structure in our code.
Co-authored-by: Ona <no-reply@ona.com>
* Exempt dedicated installations from sunset blocking
Add isDedicatedInstallation parameter to sunset check functions.
Dedicated installations always return false (not blocked) regardless
of feature flag state.
Changes:
- isUserLoginBlockedBySunset: add isDedicatedInstallation param
- isWorkspaceStartBlockedBySunset: add isDedicatedInstallation param
- UserController: pass config.isDedicatedInstallation to login check
- WorkspaceServiceAPI: inject Config and pass isDedicatedInstallation
This ensures the sunset only affects gitpod.io (PAYG) and not
dedicated installations.
Co-authored-by: Ona <no-reply@ona.com>
* update login page for Gitpod classic `gitpod.io` users
* fix
* Improve sunset UI: use primary button and remove redundant subheading
Co-authored-by: Ona <no-reply@ona.com>
* Update sunset UI heading to focus on Ona value proposition
Co-authored-by: Ona <no-reply@ona.com>
---------
Co-authored-by: Ona <no-reply@ona.com>
Co-authored-by: Siddhant Khare <siddhant@gitpod.io>
Co-authored-by: Cornelius A. Ludmann <github@cornelius-ludmann.de>
* Remove superfluous security feature flags and always enable protections
- Remove context_env_var_validation feature flag - environment variable validation now always enabled
- Remove enable_nonce_validation feature flag - CSRF protection with nonce validation now always enabled
- Remove enable_strict_authorize_return_to feature flag - strict OAuth returnTo validation now always enabled
- Update tests to reflect permanent security measures
- Simplify code by removing conditional security logic
These security features should be permanently active rather than behind feature flags.
Addresses CLC-1618 by ensuring critical security protections cannot be accidentally disabled.
Co-authored-by: Ona <no-reply@ona.com>
* Fix unused import in envvar-prefix-context-parser.spec.ts
Remove unused Experiments import that was causing TypeScript compilation error.
Co-authored-by: Ona <no-reply@ona.com>
---------
Co-authored-by: Ona <no-reply@ona.com>
- Update GitHub Actions workflow to use bitnamilegacy/mysql image
- Configure Helm chart to pull from docker.io/bitnamilegacy registry
- Update related comments to reflect the migration
Addresses bitnami deprecation of public Debian-based images.
Bitnami has moved existing images to bitnamilegacy repository
where they remain available for development use.
Fixes: CLC-1948
Co-authored-by: Ona <no-reply@ona.com>
Redirect non-signed-in Gitpod Classic PAYG users from `gitpod.io/#`(with hash fragments) to `app.ona.com/#` while preserving hash fragments. Only applies to users accessing workspace creation URLs, not regular gitpod.io visitors.
* fix: update subscription error message and enhance upgrade plan details for Gitpod's transition to Ona
* add req. line breaks
* Fix typo in UsageBasedBillingConfig message
* fix: resolve workspace timeout parsing bug for mixed-unit durations
Fixes critical bug where organization timeout settings like '90m' (displayed as '1h30m')
were incorrectly parsed as '1m' instead of the intended 90 minutes.
Root cause: Custom parsing logic used:
- duration.slice(-1) to get unit (only last character)
- parseInt(duration.slice(0, -1), 10) to get value (stopped at first non-digit)
This caused '1h30m' → '1m', '2h15m' → '2m', etc.
Solution: Replace custom validation with @arcjet/duration library:
- Exact TypeScript port of Go's time.ParseDuration
- Handles all Go duration formats correctly including mixed units
- Zero dependencies, professionally maintained
- Comprehensive test coverage added
Impact: Organization admins can now set workspace timeouts like '90m'
and they will correctly result in 90-minute timeouts instead of 1-minute.
Co-authored-by: Ona <no-reply@ona.com>
* fix: migrate from @arcjet/duration to parse-duration library
- Replace @arcjet/duration with parse-duration for better Go duration format support
- Fix workspace timeout validation to handle milliseconds instead of seconds
- Add regex validation to reject bare numbers without units
- Update parseGoDurationToMs to handle null returns properly
- All 108 tests passing, mixed-unit duration bug completely resolved
The @arcjet/duration library had usage warnings and parsing issues with
mixed-unit durations like '1h30m' being incorrectly parsed as '1m'.
parse-duration is better maintained (367 dependents, 285k weekly downloads),
has zero dependencies, and provides perfect Go duration format compatibility.
Co-authored-by: Ona <no-reply@ona.com>
* fix: handle empty/whitespace strings in parseGoDurationToMs
The parseGoDurationToMs function was throwing errors for empty strings
and whitespace-only strings, but these should return 0 duration.
This was causing failures in public-api tests that expect empty strings
to be converted to 0 duration.
- Handle empty or whitespace-only strings as 0 duration
- Maintain existing error handling for invalid duration formats
- All tests now pass (108/108 gitpod-protocol, 87/87 public-api)
Co-authored-by: Ona <no-reply@ona.com>
---------
Co-authored-by: Ona <no-reply@ona.com>
* feat(agent-smith): implement filesystem signature scanning
- Add filesystem scanning capability to detect suspicious files in workspaces
- Scan workspace directories directly from WorkingArea/{InstanceID} paths
- Support filesystem signatures with filename patterns and regex matching
- Add FilesystemScanning configuration with WorkingArea path
- Integrate filesystem detection with existing signature classifier
- Fix regex pattern matching in signature matching logic
- Add comprehensive filesystem scanning tests
- Update example configuration with filesystem signatures
Co-authored-by: Ona <no-reply@ona.com>
* cleanup
* Use a separate func for matching for filesystem signatures
* Fix logging for successful match
* Simplify & no metrics
Co-authored-by: Ona <no-reply@ona.com>
* Don't get fooled by the match
* Revert "Don't get fooled by the match"
This reverts commit 124b7ac47b9a119d15f0a859cd258d8475839fed.
Co-authored-by: Ona <no-reply@ona.com>
* Cleanup
Co-authored-by: Ona <no-reply@ona.com>
* More cleanup
* Renaming and metric removal
* Fix build
---------
Co-authored-by: Ona <no-reply@ona.com>
- Install netcat-openbsd (binary name: nc) for network testing
- Install redis-tools (binary name: redis-cli) for Redis operations
- Both tools are commonly needed for debugging and development
Co-authored-by: Ona <no-reply@ona.com>
* feat: implement CSRF protection for OAuth flows with nonce validation
- Add NonceService for cryptographically secure nonce generation and validation
- Include nonce in JWT state for OAuth authorization requests
- Store nonce in secure httpOnly cookie with SameSite=strict
- Validate nonce matches between state and cookie in auth callback
- Add origin/referer header validation for additional CSRF protection
- Use timing-safe comparison to prevent timing attacks
- Clear nonce cookie after successful validation or on error
This prevents CSRF attacks where malicious sites could initiate OAuth flows
on behalf of users by ensuring authorization requests originate from Gitpod.
Co-authored-by: Ona <no-reply@ona.com>
* refactor: consolidate fragment protection and fix context provider conflict
Co-authored-by: Ona <no-reply@ona.com>
* fix: handle GitHub OAuth api subdomain edge case with secure redirect
Co-authored-by: Ona <no-reply@ona.com>
* fix: simplify api subdomain redirect test to avoid dependency injection complexity
Replace complex Authenticator dependency injection test with simple unit test
that focuses on the core logic without requiring all service dependencies.
This makes the test more reliable and easier to maintain while still validating
the critical api subdomain detection logic for the GitHub OAuth edge case.
Co-authored-by: Ona <no-reply@ona.com>
* docs: update domain examples to use gitpod.io instead of preview domains
Update test examples and documentation to use production-appropriate
domain examples (gitpod.io) instead of specific preview environment
domains for better clarity and maintainability.
Co-authored-by: Ona <no-reply@ona.com>
* fix cookie
Co-authored-by: Ona <no-reply@ona.com>
* Update authenticator.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update authenticator.ts
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* minor stuff
* cleanup old redirect logic
* cleanup
* 1
Co-authored-by: Ona <no-reply@ona.com>
* feat: add feature flags for nonce validation and strict authorize returnTo
Add two feature flags to control security features with safe defaults:
**Feature Flag 1: enable_nonce_validation (default: false)**
- Controls CSRF nonce validation in OAuth flows
- When disabled: Nonce is generated but not validated (future compatibility)
- When enabled: Full CSRF protection with nonce and origin validation
- Nonce cookies are always generated and cleared for consistency
**Feature Flag 2: enable_strict_authorize_return_to (default: false)**
- Controls returnTo validation strictness for /api/authorize endpoint
- When disabled: Falls back to login validation (broader patterns)
- When enabled: Uses strict authorize validation (limited to specific paths)
- /api/login always uses login validation regardless of flag
**Implementation Details:**
- Always generate nonce for consistency and future compatibility
- Only validate nonce when feature flag is enabled
- Always clear nonce cookies regardless of validation state
- Authorize endpoint checks flag and falls back gracefully
- Comprehensive logging for debugging and monitoring
**Backward Compatibility:**
- Default false ensures no breaking changes
- Gradual rollout possible via feature flag configuration
- Existing authentication flows continue to work
- Safe fallback behavior when flags are disabled
Co-authored-by: Ona <no-reply@ona.com>
* fix: validate OAuth callback origin against SCM provider domain
Update NonceService.validateOrigin to check request origin against the
expected SCM provider domain instead of Gitpod's own domain. This fixes
the CSRF protection logic for OAuth callbacks which legitimately come
from external providers (github.com, gitlab.com, etc.).
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
* 1
* remove the origin check logic
* update sorry url
* move files
* use safeRedirect for redirect
* 1
* [server] minor refactor/renames
* moah changes
---------
Co-authored-by: Ona <no-reply@ona.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Gero Posmyk-Leinemann <gero@gitpod.io>
Co-authored-by: Claude <noreply@anthropic.com>
* [dev] Use "-ping" in redis-cli, which is compatible with newer versions
* Fix ping invocation
Co-authored-by: iQQBot <tianshi8650@gmail.com>
---------
Co-authored-by: iQQBot <tianshi8650@gmail.com>
Install SDKMAN as root (proven working approach) then create gitpod user
with symlinks to make SDKMAN accessible at /home/gitpod/.sdkman path
expected by JetBrains plugin BUILD.yaml files. This resolves the issue
where leeway run dev:preview fails in Flex environments due to SDKMAN
path mismatch.
Fixes CLC-1619
Co-authored-by: Ona <no-reply@ona.com>
The returnToPath parameter validation was vulnerable to XSS attacks using
javascript: protocol URLs with matching hostnames (e.g., javascript://gitpod.io/).
This fix ensures only HTTPS URLs with matching hostnames are trusted.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-authored-by: Claude <noreply@anthropic.com>