Sign inSign up

sbx/devin-enterprise-kit:latest

Manifest digest

sha256:6ca2c5cafca7a509ed42aae866d0e7ac17cf992808c5b5229fa7d11d3dcc8fa4

Last pushed

6 days by sbx

Type

Sandbox Kit

Manifest digest

sha256:6ca2c5cafca7a509ed42aae866d0e7ac17cf992808c5b5229fa7d11d3dcc8fa4

yaml
schemaVersion: "2"
kind: sandbox
name: devin-enterprise
version: 0.1.0
displayName: Devin (Enterprise)
description: Devin CLI by Cognition, pinned to a Devin Enterprise deployment (<org>.devinenterprise.com). The sibling `devin` kit targets Cognition's public SaaS; this fork repoints auth, API, and model backends at the enterprise endpoints and takes the org slug as a kit argument.
args:
    org:
        required: true
        description: Enterprise org slug — "acme" for acme.devinenterprise.com
        pattern: ^[a-z0-9][a-z0-9-]*$
sandbox:
    image: docker.io/sbx/devin-image:latest
    entrypoint:
        - devin
    command:
        default:
            - --permission-mode
            - dangerous
            - --respect-workspace-trust=false
        interactive:
            - --permission-mode
            - dangerous
            - --respect-workspace-trust=false
agentInstructions:
    filename: AGENTS.md
permissions:
    network:
        allow:
            - '*.devinenterprise.com'
            - '*.enterprise.windsurf.com'
            - windsurf.com
            - server.codeium.com
            - unleash.codeium.com
            - cli.devin.ai
            - static.devin.ai
            - archive.ubuntu.com
            - security.ubuntu.com
            - ports.ubuntu.com
            - download.docker.com
setup:
    startup:
        - command:
            - sh
            - -c
            - '{ command -v apt-get && apt-get update -qq -y || true; } >/dev/null 2>&1 </dev/null &'
          user: root
          description: Update apt package cache in background
        - command:
            - sh
            - -c
            - |
              mkdir -p /etc/devin
              cat > /etc/devin/system.json <<'EOF'
              {"enterprise_host": "${{ kit.args.org }}.devinenterprise.com"}
              EOF
          user: root
          description: Pin Devin enterprise host via system.json
        - command:
            - sh
            - -c
            - |
              set -e
              [ -n "$MCP_GATEWAY_URL" ] || exit 0
              mkdir -p "$HOME/.config/devin"
              cat > "$HOME/.config/devin/mcp_config.json" <<EOF
              {
                "mcpServers": {
                  "mcp-gateway": {
                    "url": "$MCP_GATEWAY_URL",
                    "transport": "http",
                    "headers": {
                      "Authorization": "Bearer $MCP_SENTINEL_TOKEN_NAME"
                    }
                  }
                }
              }
              EOF
          user: agent
          description: Register the sandbox MCP gateway
    files:
        - path: /home/agent/.config/devin/config.json
          content: '{"auto_update": false}'
          onlyIfMissing: true
          description: Disable Devin background updates
        - path: /home/agent/.local/bin/devin
          content: |
            #!/bin/bash
            # Keep the base Devin wrapper's auth checks and login flow. Enterprise
            # credentials stay on disk because proxy-managed auth is unavailable.
            # The real CLI is installed alongside this wrapper as devin-cli.
            #
            # `set -e` is deliberately NOT set. Every failure below is checked explicitly,
            # and several checks depend on reading a non-zero status rather than dying on
            # it.
            set -uo pipefail

            credentials_file="${HOME}/.local/share/devin/credentials.toml"

            # The four states the credential file can be in, as one word. They are
            # exhaustive and mutually exclusive, which is what lets the dispatch below
            # close with a plain `else`.
            #
            #   absent     — no file, or no windsurf_api_key line in it
            #   empty      — the key is present but blank, which the CLI treats as
            #                logged-in-with-nothing and will not overwrite on its own
            #   sentinel   — a proxy placeholder left by the managed wrapper
            #   credential — a real key sitting in the container
            credential_state() {
                if [[ ! -f "${credentials_file}" ]] ||
                    ! grep -Eq '^[[:space:]]*windsurf_api_key[[:space:]]*=' "${credentials_file}"; then
                    echo absent
                elif grep -Eq '^[[:space:]]*windsurf_api_key[[:space:]]*=[[:space:]]*""[[:space:]]*$' "${credentials_file}"; then
                    echo empty
                elif grep -Fqx 'windsurf_api_key = "devin-proxy-managed"' "${credentials_file}"; then
                    echo sentinel
                else
                    echo credential
                fi
            }

            # `devin-cli auth status` exits 0 whether or not a session exists in some
            # releases, so its message is checked as well as its status. It is captured
            # into a variable rather than piped into grep: `grep -q` exits on first match,
            # which can leave devin-cli killed by SIGPIPE, and under `pipefail` that
            # failure becomes the pipeline's status and would mask the successful match.
            state=$(credential_state)
            login_required=false
            if [[ "${state}" == absent || "${state}" == empty ]]; then
                login_required=true
            elif [[ "${state}" == sentinel ]]; then
                # The placeholder is only as good as the key the host holds behind it. If
                # that key has been revoked or rotated away, the file is worthless — drop
                # it and log in again rather than starting an agent that will fail on its
                # first request.
                if ! status=$(devin-cli auth status 2>&1) ||
                    [[ "${status,,}" == *"failed to fetch"* ]] ||
                    [[ "${status,,}" == *"not logged in"* ]]; then
                    rm -f "${credentials_file}"
                    state=absent
                    login_required=true
                fi
            else
                # state == credential. A real key is on disk; find out whether it works
                # before deciding. Unlike the sentinel branch above, a transport failure
                # here is fatal rather than a trigger for re-login: this key may be the
                # user's own, and silently discarding it on a network blip would be worse
                # than stopping.
                if ! status=$(devin-cli auth status 2>&1); then
                    echo "Failed to read Devin authentication status." >&2
                    exit 1
                fi
                if [[ "${status,,}" == *"failed to fetch"* ]]; then
                    echo "Failed to validate Devin authentication." >&2
                    exit 1
                fi
                [[ "${status,,}" == *"not logged in"* ]] && login_required=true
            fi

            if [[ "${login_required}" == true ]]; then
                echo "Not authenticated. Starting Devin login..."
                # An empty key reads as logged-in to the CLI, so `auth login` would refuse
                # to run. Clearing the session first is what makes the login below
                # reachable from that state.
                if [[ "${state}" == empty ]] && ! devin-cli auth logout >/dev/null 2>&1; then
                    echo "Failed to clear empty Devin credentials." >&2
                    exit 1
                fi
                # No browser runs in the sandbox, so the default localhost redirect never
                # comes back. --force-manual-token-flow is Devin's own answer for that
                # case, documented for remote and SSH sessions: it prints a URL to open on
                # the host and reads the token back here.
                if ! devin-cli auth login --force-manual-token-flow; then
                    echo "Login failed." >&2
                    exit 1
                fi
                # Login returns as soon as it has written the durable key. This status
                # call is what puts that key on the wire to a Devin host, which is the
                # moment the proxy can capture it — before secure_credentials below
                # replaces the local copy.
                if ! status=$(devin-cli auth status 2>&1) ||
                    [[ "${status,,}" == *"failed to fetch"* ]] ||
                    [[ "${status,,}" == *"not logged in"* ]]; then
                    echo "Failed to validate Devin login." >&2
                    exit 1
                fi
            fi

            # exec so devin-cli replaces this wrapper rather than running underneath it:
            # Ctrl-C and SIGTERM then reach the CLI directly instead of a shell that would
            # have to forward them.
            exec devin-cli "$@"
          mode: "0755"
          description: Entrypoint — validate credentials, login if needed, then exec devin-cli