> ## Documentation Index
> Fetch the complete documentation index at: https://docs.devin.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Libreria di template

> Blueprint pronti da copiare e incollare per linguaggi comuni, registry privati e infrastruttura Enterprise.

Blueprint pronti da copiare e incollare per linguaggi e casi d'uso comuni. Ogni template è autonomo. Combinali per comporre la configurazione completa.

Per una panoramica completa di ogni campo, consulta il [riferimento del blueprint](/it/onboard-devin/environment/blueprint-reference).

<Info>
  **Secrets:** I template fanno riferimento ai secret tramite `$SECRET_NAME`. Configurali nella scheda **Secrets** all'interno di ciascun editor di blueprint prima di usare un template. Non inserire mai credenziali in chiaro nel blueprint.
</Info>

***

<div id="quick-start">
  ## Guida rapida
</div>

Blueprint essenziali per le configurazioni più comuni. Copiane uno, incollalo nell'editor dei blueprint e il gioco è fatto.

<AccordionGroup>
  <Accordion title="Progetto Node.js">
    ```yaml theme={null}
    initialize: |
      npm install -g pnpm

    maintenance: |
      pnpm install

    knowledge:
      - name: lint
        contents: |
          Esegui `pnpm lint` per verificare eventuali errori.
      - name: test
        contents: |
          Esegui `pnpm test` per la suite completa.
    ```
  </Accordion>

  <Accordion title="Progetto Python">
    ```yaml theme={null}
    initialize: |
      curl -LsSf https://astral.sh/uv/install.sh | sh

    maintenance: |
      uv sync

    knowledge:
      - name: lint
        contents: |
          Esegui `uv run ruff check .` per il linting.
      - name: test
        contents: |
          Esegui `uv run pytest` per la suite completa.
    ```
  </Accordion>

  <Accordion title="Full-stack (Node + Python)">
    ```yaml theme={null}
    initialize:
      - name: Install pnpm
        run: npm install -g pnpm
      - name: Install uv
        run: curl -LsSf https://astral.sh/uv/install.sh | sh

    maintenance:
      - name: Dipendenze frontend
        run: (cd frontend && pnpm install)
      - name: Dipendenze backend
        run: (cd backend && uv sync)

    knowledge:
      - name: structure
        contents: |
          - `frontend/` — app React (pnpm)
          - `backend/` — API Python (uv)
      - name: test
        contents: |
          Frontend: cd frontend && pnpm test
          Backend: cd backend && uv run pytest
    ```
  </Accordion>
</AccordionGroup>

***

<div id="repository-blueprints">
  ## Blueprint dei repository
</div>

Passaggi di build per ciascun repo, gestione delle dipendenze e voci di Knowledge. Configurali in **Settings > Ambiente > Blueprint > \[il tuo repo]**.

<div id="python">
  ### Python
</div>

<Tabs>
  <Tab title="uv (consigliato)">
    Configurazione consigliata per i progetti Python che usano [uv](https://docs.astral.sh/uv/) per la gestione delle dipendenze.

    ```yaml theme={null}
    initialize: |
      curl -LsSf https://astral.sh/uv/install.sh | sh

    maintenance: |
      uv sync

    knowledge:
      - name: lint
        contents: |
          uv run ruff check .

          Correzione automatica:
          uv run ruff check --fix .

      - name: test
        contents: |
          uv run pytest

      - name: build
        contents: |
          uv run python -m build
    ```
  </Tab>

  <Tab title="pip + venv">
    Configurazione Python tradizionale con pip e venv. Da usare quando il progetto si basa su `requirements.txt`.

    ```yaml theme={null}
    initialize: |
      python3 -m venv .venv

    maintenance: |
      source .venv/bin/activate
      pip install -r requirements.txt

    knowledge:
      - name: lint
        contents: |
          source .venv/bin/activate
          flake8 .

      - name: test
        contents: |
          source .venv/bin/activate
          pytest

      - name: build
        contents: |
          source .venv/bin/activate
          python -m build
    ```
  </Tab>
</Tabs>

<div id="nodejs">
  ### Node.js
</div>

<Tabs>
  <Tab title="npm">
    Configurazione Standard di Node.js con npm.

    ```yaml theme={null}
    initialize: |
      nvm install 20
      nvm use 20

    maintenance: |
      npm install

    knowledge:
      - name: lint
        contents: |
          npx eslint .

      - name: test
        contents: |
          npm test

      - name: build
        contents: |
          npm run build
    ```

    <Info>
      Usa `npm install` (non `npm ci`) in `maintenance`. Esegue un aggiornamento incrementale, mentre `npm ci` elimina `node_modules` e reinstalla tutto da zero a ogni sessione.
    </Info>
  </Tab>

  <Tab title="pnpm">
    Per i progetti che usano pnpm.

    ```yaml theme={null}
    initialize: |
      npm install -g pnpm

    maintenance: |
      pnpm install --frozen-lockfile

    knowledge:
      - name: lint
        contents: |
          pnpm lint

      - name: test
        contents: |
          pnpm test

      - name: build
        contents: |
          pnpm build
    ```
  </Tab>
</Tabs>

<div id="go">
  ### Go
</div>

Configurazione standard di Go con moduli.

```yaml theme={null}
initialize: |
  GO_VERSION=1.23.5
  ARCH=$(dpkg --print-architecture)
  curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${ARCH}.tar.gz" \
    | sudo tar -xz -C /usr/local
  echo 'export PATH="/usr/local/go/bin:$HOME/go/bin:$PATH"' \
    | sudo tee /etc/profile.d/golang.sh > /dev/null

  go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest

maintenance: |
  go mod download

knowledge:
  - name: lint
    contents: |
      golangci-lint run

  - name: test
    contents: |
      go test ./...

  - name: build
    contents: |
      go build ./...
```

<div id="java">
  ### Java
</div>

<Tabs>
  <Tab title="Gradle">
    Configurazione di Java con Gradle.

    <Info>JDK 17 è **preinstallato** nell'immagine di base di Devin. Salta il passaggio di installazione del JDK se OpenJDK 17 predefinito è sufficiente.</Info>

    ```yaml theme={null}
    initialize:
      - name: Install JDK 17
        run: |
          sudo apt-get update -qq
          sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-17-jdk-headless
          echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' \
            | sudo tee /etc/profile.d/java.sh > /dev/null

      - name: Install Gradle
        run: |
          GRADLE_VERSION=8.12
          curl -fsSL "https://services.gradle.org/distributions/gradle-${GRADLE_VERSION}-bin.zip" \
            -o /tmp/gradle.zip
          sudo unzip -qo /tmp/gradle.zip -d /opt
          sudo ln -sf /opt/gradle-${GRADLE_VERSION}/bin/gradle /usr/local/bin/gradle
          rm /tmp/gradle.zip

    maintenance: |
      ./gradlew dependencies

    knowledge:
      - name: lint
        contents: |
          ./gradlew check

      - name: test
        contents: |
          ./gradlew test

      - name: build
        contents: |
          ./gradlew build
    ```
  </Tab>

  <Tab title="Maven">
    Configurazione di Java con Maven.

    <Info>JDK 17 è **preinstallato** nell'immagine di base di Devin. Salta il passaggio di installazione del JDK se OpenJDK 17 predefinito è sufficiente.</Info>

    ```yaml theme={null}
    initialize:
      - name: Install JDK 17
        run: |
          sudo apt-get update -qq
          sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-17-jdk-headless
          echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' \
            | sudo tee /etc/profile.d/java.sh > /dev/null

      - name: Install Maven
        run: |
          MAVEN_VERSION=3.9.9
          curl -fsSL "https://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz" \
            | sudo tar -xz -C /opt
          sudo ln -sf /opt/apache-maven-${MAVEN_VERSION}/bin/mvn /usr/local/bin/mvn

    maintenance: |
      mvn dependency:resolve

    knowledge:
      - name: test
        contents: |
          mvn test

      - name: build
        contents: |
          mvn package
    ```
  </Tab>
</Tabs>

<div id="ruby-on-rails">
  ### Ruby on Rails
</div>

Configurazione di Rails con PostgreSQL.

```yaml theme={null}
initialize:
  - name: Install Ruby 3.3
    run: |
      sudo apt-get update -qq
      sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq ruby-full libpq-dev postgresql-client

maintenance: |
  bundle install
  rails db:migrate

knowledge:
  - name: lint
    contents: |
      bundle exec rubocop

  - name: test
    contents: |
      bundle exec rspec

  - name: build
    contents: |
      rails assets:precompile
```

<div id="rust">
  ### Rust
</div>

Configurazione Rust standard con Cargo.

<Info>**Rust** (tramite rustup) e **Cargo** sono **preinstallati** nell'immagine di base di Devin. Salta il passaggio di installazione se la toolchain stabile predefinita è sufficiente. Devi solo scaricare le dipendenze.</Info>

```yaml theme={null}
initialize: |
  curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
  source ~/.cargo/env

maintenance: |
  cargo fetch

knowledge:
  - name: lint
    contents: |
      cargo clippy -- -D warnings

  - name: test
    contents: |
      cargo test

  - name: build
    contents: |
      cargo build --release
```

<div id="monorepos">
  ### Monorepo
</div>

<Tabs>
  <Tab title="Multilingue">
    Monorepo con frontend Node.js e backend Python. Ogni sottoprogetto ha le proprie voci di Knowledge.

    ```yaml theme={null}
    initialize:
      - name: Install pnpm
        run: npm install -g pnpm
      - name: Install uv
        run: curl -LsSf https://astral.sh/uv/install.sh | sh

    maintenance:
      - name: Install frontend dependencies
        run: (cd packages/frontend && pnpm install)
      - name: Install backend dependencies
        run: (cd packages/backend && uv sync)
      - name: Build shared library
        run: (cd packages/shared && pnpm install && pnpm build)

    knowledge:
      - name: structure
        contents: |
          Questo è un monorepo con tre package:
          - `packages/frontend` — app React (TypeScript, pnpm)
          - `packages/backend` — API Python (FastAPI, uv)
          - `packages/shared` — utilità TypeScript condivise (da buildare prima del frontend)
      - name: frontend
        contents: |
          Esegui `cd packages/frontend && pnpm dev` per avviare il server di sviluppo.
          Esegui `cd packages/frontend && pnpm lint` per eseguire il lint.
          Esegui `cd packages/frontend && pnpm test` per eseguire i test.
      - name: backend
        contents: |
          Esegui `cd packages/backend && uv run uvicorn app.main:app --reload` per avviare l'API.
          Esegui `cd packages/backend && uv run ruff check .` per eseguire il lint.
          Esegui `cd packages/backend && uv run pytest` per eseguire i test.
    ```

    <Tip>
      Usa le subshell `(cd dir && command)` invece di `cd dir && command`, così la directory di lavoro viene reimpostata tra un passaggio e l'altro.
    </Tip>
  </Tab>

  <Tab title="Versioni multiple di JDK">
    Un monorepo Java in cui servizi diversi richiedono versioni diverse del JDK. Installa entrambi i JDK durante la configurazione, poi usa le voci di `knowledge` per indicare a Devin quale `JAVA_HOME` usare per ciascun servizio.

    ```yaml theme={null}
    initialize:
      - name: Install JDK 17 (primary)
        run: |
          sudo apt-get update -qq
          sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-17-jdk-headless
          echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' \
            | sudo tee /etc/profile.d/java.sh > /dev/null

      - name: Install JDK 11 (legacy service)
        run: |
          sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-11-jdk-headless

    maintenance:
      - name: Warm dependency caches
        run: |
          export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
          (cd services/api && ./gradlew dependencies --refresh-dependencies)

          export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
          (cd services/legacy && ./gradlew dependencies --refresh-dependencies)

    knowledge:
      - name: build_api
        contents: |
          Esegui la build del servizio API (JDK 17):
            JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 \
            cd services/api && ./gradlew clean build
      - name: build_legacy
        contents: |
          Esegui la build del servizio legacy (JDK 11):
            JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 \
            cd services/legacy && ./gradlew clean build
      - name: test_all
        contents: |
          Esegui i test per tutti i servizi:
            JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 \
            (cd services/api && ./gradlew test)

            JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64 \
            (cd services/legacy && ./gradlew test)
    ```
  </Tab>
</Tabs>

***

<div id="private-package-registries">
  ## Registry privati di pacchetti
</div>

Configura i gestori di pacchetti per risolvere le dipendenze tramite registry privati. Impostali in **Settings > Environment > Blueprint > Configurazione a livello di org** (oppure a livello di repo, se serve solo per una repo).

<Warning>
  **La configurazione delle credenziali deve stare in `maintenance`, non in `initialize`.** I passaggi che scrivono segreti (password del registry, auth token) nei file di configurazione devono usare `maintenance`, in modo che le credenziali vengano
  ricaricate a ogni sessione. I segreti vengono rimossi prima che lo snapshot venga salvato, quindi i file di configurazione scritti durante `initialize` non avranno credenziali valide all'avvio delle sessioni.
</Warning>

<Info>
  Se il tuo registry privato usa una CA aziendale, assicurati prima che il [certificato CA](#corporate-ca-certificate) sia installato a livello Enterprise. La configurazione seguente presuppone che l'attendibilità HTTPS sia
  già configurata.
</Info>

<div id="nodejs-registries">
  ### Registry Node.js
</div>

<Tabs>
  <Tab title="npm (ambito)">
    Configura npm per risolvere i pacchetti con ambito (ad es. `@myorg/*`) da un registry privato, mentre i pacchetti pubblici continuano a provenire dal registry npm predefinito.

    <Accordion title="Segreti richiesti">- `GITHUB_PACKAGES_TOKEN` — Token di accesso personale o token GitHub App con ambito `read:packages`</Accordion>

    ```yaml theme={null}
    maintenance:
      - name: Configure npm scoped registry
        run: |
          npm config set @myorg:registry https://npm.pkg.github.com
          npm config set //npm.pkg.github.com/:_authToken $GITHUB_PACKAGES_TOKEN
    ```

    <Tip>
      Sostituisci `@myorg` con il tuo scope npm. URL comuni dei registry privati:

      * **GitHub Packages:** `https://npm.pkg.github.com`
      * **Artifactory:** `https://artifactory.example.com/artifactory/api/npm/npm-virtual`
      * **Nexus:** `https://nexus.example.com/repository/npm-group`
      * **GitLab:** `https://gitlab.example.com/api/v4/packages/npm`
      * **AWS CodeArtifact:** `https://<domain>.d.codeartifact.<region>.amazonaws.com/npm/<repo>`
    </Tip>
  </Tab>

  <Tab title="npm (mirror completo)">
    Instrada **tutti** i pacchetti npm attraverso il tuo registry privato (non solo i pacchetti con ambito).

    <Accordion title="Segreti richiesti">
      * `NPM_REGISTRY_URL` — URL completo del tuo registry npm (ad es. `https://artifactory.example.com/artifactory/api/npm/npm-virtual`) - `NPM_REGISTRY_HOST` — Solo hostname, senza protocollo (ad es.
        `artifactory.example.com`) - `REGISTRY_TOKEN` — Token di autenticazione npm per il registry
    </Accordion>

    ```yaml theme={null}
    maintenance:
      - name: Configure npm to use private registry
        run: |
          npm config set registry $NPM_REGISTRY_URL
          npm config set //${NPM_REGISTRY_HOST}/:_authToken $REGISTRY_TOKEN
          npm config set strict-ssl true
    ```
  </Tab>

  <Tab title="pnpm">
    Configura pnpm per risolvere i pacchetti da un registry privato.

    <Accordion title="Segreti richiesti">
      * `NPM_REGISTRY_URL` — URL completo del tuo registry npm - `NPM_REGISTRY_HOST` — Solo hostname, senza protocollo - `REGISTRY_TOKEN` — Token di autenticazione npm per il registry
    </Accordion>

    ```yaml theme={null}
    initialize:
      - name: Install pnpm
        run: npm install -g pnpm

    maintenance:
      - name: Configure pnpm for private registry
        run: |
          pnpm config set registry $NPM_REGISTRY_URL
          pnpm config set //${NPM_REGISTRY_HOST}/:_authToken $REGISTRY_TOKEN
    ```
  </Tab>

  <Tab title="Yarn">
    Configura Yarn (Classic v1 o Berry v2+) per risolvere i pacchetti da un registry privato.

    <Accordion title="Segreti richiesti">- `NPM_REGISTRY_URL` — URL completo del tuo registry npm/Yarn - `REGISTRY_TOKEN` — Token di autenticazione per il registry (solo Berry)</Accordion>

    **Yarn Classic (v1):**

    ```yaml theme={null}
    initialize:
      - name: Install Yarn Classic
        run: npm install -g yarn

    maintenance:
      - name: Configure Yarn for private registry
        run: |
          yarn config set registry "$NPM_REGISTRY_URL"
          # Per i pacchetti con ambito:
          # yarn config set @myorg:registry "https://npm.pkg.github.com"
    ```

    **Yarn Berry (v2+):**

    ```yaml theme={null}
    maintenance:
      - name: Configure Yarn Berry for private registry
        run: |
          yarn config set npmRegistryServer "$NPM_REGISTRY_URL"
          yarn config set npmAuthToken "$REGISTRY_TOKEN"
          # Per i pacchetti con ambito:
          # yarn config set npmScopes.myorg.npmRegistryServer "https://npm.pkg.github.com"
          # yarn config set npmScopes.myorg.npmAuthToken "$GITHUB_PACKAGES_TOKEN"
    ```
  </Tab>
</Tabs>

<div id="python-registries">
  ### Registry Python
</div>

<Tabs>
  <Tab title="pip / uv">
    Configura pip e uv per recuperare i pacchetti dal tuo registry PyPI privato (ad es. Nexus, Artifactory).

    <Accordion title="Segreti richiesti">
      * `PYPI_REGISTRY_URL` — URL completo del tuo indice PyPI, incluse le credenziali se richieste (ad es. `https://user:token@nexus.example.com/repository/pypi-proxy/simple`)
    </Accordion>

    ```yaml theme={null}
    maintenance:
      - name: Configura pip/uv per il registry privato
        run: |
          mkdir -p ~/.config/pip
          cat > ~/.config/pip/pip.conf << EOF
          [global]
          index-url = $PYPI_REGISTRY_URL
          EOF

          echo "export UV_INDEX_URL=$PYPI_REGISTRY_URL" \
            | sudo tee /etc/profile.d/uv-registry.sh > /dev/null
    ```

    <Tip>
      URL comuni dei registry PyPI:

      * **Artifactory:** `https://artifactory.example.com/artifactory/api/pypi/pypi-virtual/simple`
      * **Nexus:** `https://nexus.example.com/repository/pypi-proxy/simple`
      * **AWS CodeArtifact:** `https://aws:TOKEN@domain-owner.d.codeartifact.region.amazonaws.com/pypi/repo/simple/`
      * **Azure Artifacts:** `https://pkgs.dev.azure.com/org/project/_packaging/feed/pypi/simple`
      * **GitLab:** `https://gitlab.example.com/api/v4/groups/<group-id>/-/packages/pypi/simple`
    </Tip>
  </Tab>

  <Tab title="Poetry">
    Configura Poetry per recuperare i pacchetti da un registry PyPI privato.

    <Accordion title="Segreti richiesti">
      * `POETRY_REGISTRY_URL` — URL completo del tuo registry compatibile con PyPI - `REGISTRY_USER` — Nome utente del registry - `REGISTRY_PASS` — Password del registry o token API
    </Accordion>

    ```yaml theme={null}
    initialize:
      - name: Installa Poetry
        run: curl -sSL https://install.python-poetry.org | python3 -

    maintenance:
      - name: Configura Poetry per il registry privato
        run: |
          poetry config repositories.private "$POETRY_REGISTRY_URL"
          poetry config http-basic.private "$REGISTRY_USER" "$REGISTRY_PASS"
    ```
  </Tab>
</Tabs>

<div id="jvm-registries">
  ### Registry JVM
</div>

<Tabs>
  <Tab title="Maven">
    Installa il JDK e configura Maven in modo che tutta la risoluzione delle dipendenze passi attraverso il tuo registry privato (ad es., Artifactory, Nexus).

    <Info>JDK 17 è **preinstallato** nell'immagine di base di Devin. Salta il passaggio di installazione se l'OpenJDK 17 predefinito è sufficiente. Ti servono solo l'installazione di Maven e la configurazione del registry.</Info>

    <Accordion title="Segreti richiesti">
      * `MAVEN_REGISTRY_URL` — URL del tuo registry Maven (ad es., `https://artifactory.example.com/artifactory/maven-virtual`) - `REGISTRY_USER` — Nome utente del registry - `REGISTRY_PASS` — Password del registry o
        token API
    </Accordion>

    ```yaml theme={null}
    initialize:
      - name: Install JDK 17
        run: |
          sudo apt-get update -qq
          sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-17-jdk-headless
          echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' \
            | sudo tee /etc/profile.d/java.sh > /dev/null

      - name: Install Maven
        run: |
          MAVEN_VERSION=3.9.9
          curl -fsSL "https://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz" \
            | sudo tar -xz -C /opt
          sudo ln -sf /opt/apache-maven-${MAVEN_VERSION}/bin/mvn /usr/local/bin/mvn

    maintenance:
      - name: Configure Maven for private registry
        run: |
          mkdir -p ~/.m2
          cat > ~/.m2/settings.xml << EOF
          <settings>
            <mirrors>
              <mirror>
                <id>private-registry</id>
                <mirrorOf>*</mirrorOf>
                <url>$MAVEN_REGISTRY_URL</url>
              </mirror>
            </mirrors>
            <servers>
              <server>
                <id>private-registry</id>
                <username>$REGISTRY_USER</username>
                <password>$REGISTRY_PASS</password>
              </server>
            </servers>
          </settings>
          EOF
    ```

    <Tip>
      Pattern di URL comuni dei registry Maven:

      * **Artifactory:** `https://artifactory.example.com/artifactory/maven-virtual`
      * **Nexus:** `https://nexus.example.com/repository/maven-public`
      * **Azure Artifacts:** `https://pkgs.dev.azure.com/org/project/_packaging/feed/maven/v1`
      * **GitHub Packages:** `https://maven.pkg.github.com`
      * **GitLab:** `https://gitlab.example.com/api/v4/groups/<group-id>/-/packages/maven`
      * **AWS CodeArtifact:** `https://<domain>.d.codeartifact.<region>.amazonaws.com/maven/<repo>`
    </Tip>
  </Tab>

  <Tab title="Gradle">
    Installa il JDK e configura Gradle per risolvere tutte le dipendenze tramite il tuo registry privato.

    <Info>JDK 17 è **preinstallato** nell'immagine di base di Devin. Salta il passaggio di installazione del JDK se la versione predefinita è sufficiente.</Info>

    <Accordion title="Segreti richiesti">- `GRADLE_REGISTRY_URL` — URL del tuo registry Gradle/Maven - `REGISTRY_USER` — Nome utente del registry - `REGISTRY_PASS` — Password del registry o token API</Accordion>

    ```yaml theme={null}
    initialize:
      - name: Install JDK 17
        run: |
          sudo apt-get update -qq
          sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-17-jdk-headless
          echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' \
            | sudo tee /etc/profile.d/java.sh > /dev/null

      - name: Install Gradle
        run: |
          GRADLE_VERSION=8.12
          curl -fsSL "https://services.gradle.org/distributions/gradle-${GRADLE_VERSION}-bin.zip" \
            -o /tmp/gradle.zip
          sudo unzip -qo /tmp/gradle.zip -d /opt
          sudo ln -sf /opt/gradle-${GRADLE_VERSION}/bin/gradle /usr/local/bin/gradle
          rm /tmp/gradle.zip

    maintenance:
      - name: Configure Gradle for private registry
        run: |
          mkdir -p ~/.gradle
          cat > ~/.gradle/init.gradle << EOF
          allprojects {
              repositories {
                  maven {
                      url "$GRADLE_REGISTRY_URL"
                      credentials {
                          username = "$REGISTRY_USER"
                          password = "$REGISTRY_PASS"
                      }
                      allowInsecureProtocol = false
                  }
              }
          }
          EOF
    ```
  </Tab>
</Tabs>

<div id="other-registries">
  ### Altri registry
</div>

<AccordionGroup>
  <Accordion title="Proxy dei moduli Go">
    Installa Go e configuralo per risolvere i moduli tramite un proxy privato per i moduli (ad es. Athens, Artifactory o un endpoint `GOPROXY`).

    <Accordion title="Segreti richiesti">
      * `GO_PROXY_URL` — URL del tuo proxy per i moduli Go (ad es. `https://athens.corp.internal`)
      * `GIT_TOKEN` — token di accesso personale per repo Git private che ospitano moduli Go
    </Accordion>

    ```yaml theme={null}
    initialize:
      - name: Install Go
        run: |
          GO_VERSION=1.23.5
          ARCH=$(dpkg --print-architecture)
          curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${ARCH}.tar.gz" \
            | sudo tar -xz -C /usr/local
          echo 'export PATH="/usr/local/go/bin:$HOME/go/bin:$PATH"' \
            | sudo tee /etc/profile.d/golang.sh > /dev/null

      - name: Configure Go for private modules
        run: |
          cat << 'GOENV' | sudo tee /etc/profile.d/go-private.sh > /dev/null
          export GOPROXY="$GO_PROXY_URL,direct"
          export GONOSUMCHECK="corp.internal/*,github.com/myorg/*"
          export GOPRIVATE="corp.internal/*,github.com/myorg/*"
          GOENV

    maintenance:
      - name: Authenticate Go private modules
        run: |
          git config --global url."https://$GIT_TOKEN@github.com/myorg/".insteadOf "https://github.com/myorg/"
    ```

    <Tip>
      Pattern URL comuni per i proxy Go:

      * **Artifactory:** `https://artifactory.example.com/artifactory/go-virtual`
      * **Nexus:** `https://nexus.example.com/repository/go-proxy`
      * **Athens:** `https://athens.corp.internal`
    </Tip>
  </Accordion>

  <Accordion title=".NET / NuGet">
    Configura NuGet per usare un feed privato come origine dei pacchetti.

    <Accordion title="Segreti richiesti">
      * `NUGET_SOURCE_URL` — URL del tuo feed NuGet
      * `NUGET_API_KEY` — API key o PAT per il feed
    </Accordion>

    ```yaml theme={null}
    initialize:
      - name: Install .NET SDK
        run: |
          curl -fsSL https://dot.net/v1/dotnet-install.sh | bash -s -- --channel 8.0
          echo 'export PATH="$HOME/.dotnet:$PATH"' \
            | sudo tee /etc/profile.d/dotnet.sh > /dev/null

    maintenance:
      - name: Configure NuGet for private feed
        run: |
          dotnet nuget add source "$NUGET_SOURCE_URL" \
            --name private \
            --username any \
            --password "$NUGET_API_KEY" \
            --store-password-in-clear-text 2>/dev/null || \
          dotnet nuget update source private \
            --source "$NUGET_SOURCE_URL" \
            --username any \
            --password "$NUGET_API_KEY" \
            --store-password-in-clear-text
    ```
  </Accordion>

  <Accordion title="Docker">
    Configura Docker per scaricare da un registry di container privato.

    <Accordion title="Segreti richiesti">
      * `DOCKER_MIRROR_URL` *(facoltativo)* — URL del mirror Docker Hub (ad es., `https://mirror.corp.internal`)
      * `DOCKER_REGISTRY_URL` — URL del tuo registry di container privato (ad es., `registry.corp.internal:5000`)
      * `DOCKER_REGISTRY_USER` — Nome utente del registry
      * `DOCKER_REGISTRY_PASS` — Password del registry o token API
    </Accordion>

    ```yaml theme={null}
    initialize:
      - name: Create Docker config directory
        run: sudo mkdir -p /etc/docker

    maintenance:
      - name: Configure Docker for private registry
        run: |
          # Configura il mirror del registry (opzionale — instrada i pull di Docker Hub attraverso il tuo registry)
          cat << EOF | sudo tee /etc/docker/daemon.json > /dev/null
          {
            "registry-mirrors": ["$DOCKER_MIRROR_URL"]
          }
          EOF
          sudo systemctl restart docker || true

          # Accedi al container registry privato
          echo "$DOCKER_REGISTRY_PASS" | docker login "$DOCKER_REGISTRY_URL" \
            --username "$DOCKER_REGISTRY_USER" \
            --password-stdin
    ```

    <Tip>
      URL comuni dei container registry:

      * **Amazon ECR:** `<account-id>.dkr.ecr.<region>.amazonaws.com`
      * **Azure Container Registry:** `<name>.azurecr.io`
      * **Google Artifact Registry:** `<region>-docker.pkg.dev`
      * **GitHub Container Registry:** `ghcr.io`
      * **GitLab Container Registry:** `registry.gitlab.example.com`
      * **Nexus:** `https://nexus.example.com:8443`
      * **JFrog:** `<name>.jfrog.io`
    </Tip>
  </Accordion>

  <Accordion title="Rust / Cargo">
    Configura Cargo in modo che risolva i crate da un registry privato.

    <Info>
      **Rust** (tramite rustup) e **Cargo** sono **già preinstallati** nell'immagine di base di Devin. Salta il passaggio di installazione se la toolchain stabile predefinita è sufficiente. È necessaria solo la configurazione del registry.
    </Info>

    <Accordion title="Segreti richiesti">
      * `CARGO_REGISTRY_INDEX` — URL dell'indice del registry privato (ad es. `sparse+https://cargo.corp.internal/api/v1/crates/`)
      * `CARGO_REGISTRY_TOKEN` — token di autenticazione per il registry privato
    </Accordion>

    ```yaml theme={null}
    initialize:
      - name: Install Rust
        run: |
          curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
            | sh -s -- -y --default-toolchain stable
          echo 'source "$HOME/.cargo/env"' \
            | sudo tee /etc/profile.d/rust.sh > /dev/null

    maintenance:
      - name: Configure Cargo for private registry
        run: |
          mkdir -p ~/.cargo
          cat > ~/.cargo/config.toml << EOF
          [registries.private]
          index = "$CARGO_REGISTRY_INDEX"
          token = "$CARGO_REGISTRY_TOKEN"

          [source.crates-io]
          replace-with = "private"

          [source.private]
          registry = "$CARGO_REGISTRY_INDEX"
          EOF
    ```

    <Tip>
      Se devi solo **aggiungere** un registry privato senza sostituire crates.io, rimuovi le sezioni `[source.crates-io]` e `[source.private]` e usa `cargo install --registry private` oppure `[dependencies] my-crate = { version = "1.0", registry = "private" }` in `Cargo.toml`.
    </Tip>
  </Accordion>

  <Accordion title="Ruby / Bundler">
    Installa Ruby e configura Bundler per risolvere le dipendenze gem da un server Gem privato.

    <Accordion title="Segreti richiesti">
      * `GEM_SERVER_URL` — URL del tuo server Gem privato (ad es. `https://artifactory.example.com/artifactory/api/gems/gems-virtual`)
      * `REGISTRY_USER` — Nome utente del registry
      * `REGISTRY_PASS` — Password del registry o token API
    </Accordion>

    ```yaml theme={null}
    initialize:
      - name: Install Ruby
        run: |
          sudo apt-get update -qq
          sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq ruby-full

    maintenance:
      - name: Configure Bundler for private gem server
        run: |
          bundle config set mirror.https://rubygems.org "$GEM_SERVER_URL"
          bundle config set "$GEM_SERVER_URL" "$REGISTRY_USER:$REGISTRY_PASS"
    ```

    <Tip>
      Pattern URL comuni per i server gem:

      * **Artifactory:** `https://artifactory.example.com/artifactory/api/gems/gems-virtual`
      * **Nexus:** `https://nexus.example.com/repository/rubygems-proxy`
      * **Gemfury:** `https://gem.fury.io/<org>`
    </Tip>
  </Accordion>

  <Accordion title="PHP / Composer">
    Installa PHP e configura Composer per recuperare i pacchetti da un registry privato Packagist o Satis.

    <Accordion title="Segreti richiesti">
      * `COMPOSER_REGISTRY_URL` — URL del tuo registry Composer privato (ad es. `https://repo.packagist.com/<org>`)
      * `REGISTRY_USER` — Nome utente del registry
      * `REGISTRY_PASS` — Password del registry o token API
    </Accordion>

    ```yaml theme={null}
    initialize:
      - name: Install PHP and Composer
        run: |
          sudo apt-get update -qq
          sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq \
            php-cli php-mbstring php-xml php-curl unzip

          # Installa Composer
          curl -sS https://getcomposer.org/installer | php
          sudo mv composer.phar /usr/local/bin/composer

    maintenance:
      - name: Configure Composer for private registry
        run: |
          composer config --global repositories.private \
            composer "$COMPOSER_REGISTRY_URL"

          # Autenticazione con il registry
          composer config --global http-basic.$(echo "$COMPOSER_REGISTRY_URL" \
            | sed 's|https\?://||;s|/.*||') "$REGISTRY_USER" "$REGISTRY_PASS"
    ```

    <Tip>
      Pattern URL comuni per i registry Composer:

      * **Artifactory:** `https://artifactory.example.com/artifactory/api/composer/packagist-virtual`
      * **Nexus:** `https://nexus.example.com/repository/packagist-proxy`
      * **Private Packagist:** `https://repo.packagist.com/<org>`
      * **Satis:** `https://satis.corp.internal`
    </Tip>
  </Accordion>

  <Accordion title="Aggiornamento del token di AWS CodeArtifact">
    I token AWS CodeArtifact scadono dopo 12 ore. Usa `maintenance` per configurare il comando di aggiornamento del token in modo che l'agente possa eseguirlo di nuovo quando necessario. Questo esempio configura npm, pip e Maven per usare CodeArtifact.

    <Info>
      **`awscli` è preinstallato** nell'immagine di base di Devin. Devi solo configurare l'aggiornamento del token e il registry.
    </Info>

    <Accordion title="Segreti richiesti">
      * `AWS_ACCESS_KEY_ID` e `AWS_SECRET_ACCESS_KEY` — credenziali IAM con le autorizzazioni `codeartifact:GetAuthorizationToken` e `sts:GetServiceBearerToken`
      * `CA_DOMAIN` — Nome del dominio CodeArtifact
      * `CA_DOMAIN_OWNER` — ID dell'account AWS proprietario del dominio
      * `CA_REGION` — Regione AWS (ad es., `us-east-1`)
      * `CA_NPM_REPO`, `CA_PYPI_REPO`, `CA_MAVEN_REPO` — Nomi dei repository per ciascun ecosistema
    </Accordion>

    ```yaml theme={null}
    maintenance:
      - name: Refresh CodeArtifact auth token
        run: |
          # Recupera un token aggiornato (valido per 12 ore)
          export CODEARTIFACT_AUTH_TOKEN=$(aws codeartifact get-authorization-token \
            --domain $CA_DOMAIN \
            --domain-owner $CA_DOMAIN_OWNER \
            --region $CA_REGION \
            --query authorizationToken \
            --output text)

          CA_ENDPOINT="https://${CA_DOMAIN}-${CA_DOMAIN_OWNER}.d.codeartifact.${CA_REGION}.amazonaws.com"

          # Configura npm
          npm config set registry "${CA_ENDPOINT}/npm/${CA_NPM_REPO}/"
          npm config set "//${CA_DOMAIN}-${CA_DOMAIN_OWNER}.d.codeartifact.${CA_REGION}.amazonaws.com/npm/${CA_NPM_REPO}/:_authToken" "$CODEARTIFACT_AUTH_TOKEN"

          # Configura pip
          mkdir -p ~/.config/pip
          cat > ~/.config/pip/pip.conf << EOF
          [global]
          index-url = https://aws:${CODEARTIFACT_AUTH_TOKEN}@${CA_DOMAIN}-${CA_DOMAIN_OWNER}.d.codeartifact.${CA_REGION}.amazonaws.com/pypi/${CA_PYPI_REPO}/simple/
          EOF

          # Configura Maven (opzionale)
          mkdir -p ~/.m2
          cat > ~/.m2/settings.xml << EOF
          <settings>
            <servers>
              <server>
                <id>codeartifact</id>
                <username>aws</username>
                <password>${CODEARTIFACT_AUTH_TOKEN}</password>
              </server>
            </servers>
            <mirrors>
              <mirror>
                <id>codeartifact</id>
                <mirrorOf>*</mirrorOf>
                <url>${CA_ENDPOINT}/maven/${CA_MAVEN_REPO}/</url>
              </mirror>
            </mirrors>
          </settings>
          EOF
    ```
  </Accordion>
</AccordionGroup>

***

<div id="enterprise-infrastructure">
  ## Infrastruttura Enterprise
</div>

Infrastruttura a livello di macchina valida per tutte le org e repo. Impostala in **Settings > ambiente di base di Devin** (a livello di Enterprise) oppure in **Settings > Environment > blueprint > configurazione a livello di org** (a livello di org).

<div id="network-and-connectivity">
  ### Rete e connettività
</div>

<AccordionGroup>
  <Accordion title="Certificato CA aziendale">
    La tua organizzazione utilizza un'autorità di certificazione privata per i servizi interni. Devin richiede il certificato radice per accedere ai registry interni e agli strumenti tramite HTTPS.

    <Accordion title="Segreti richiesti">- `CORP_ROOT_CA_B64` — certificato PEM codificato in Base64 della tua CA aziendale. Genera con: `cat corp-root-ca.crt | base64 -w0`</Accordion>

    ```yaml theme={null}
    initialize:
      - name: Install corporate CA certificate
        run: |
          echo "$CORP_ROOT_CA_B64" | base64 -d \
            | sudo tee /usr/local/share/ca-certificates/corp-root-ca.crt > /dev/null
          sudo update-ca-certificates
          echo 'export NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/corp-root-ca.crt' \
            | sudo tee /etc/profile.d/node-ca.sh > /dev/null
    ```
  </Accordion>

  <Accordion title="Certificati CA multipli">
    Se la tua organizzazione utilizza più certificati CA (ad es. CA distinte per diversi servizi interni).

    <Accordion title="Segreti richiesti">- `CORP_ROOT_CA_B64` — certificato CA principale codificato in Base64 - `CORP_INTERMEDIATE_CA_B64` — certificato CA intermedio codificato in Base64</Accordion>

    ```yaml theme={null}
    initialize:
      - name: Install corporate CA certificates
        run: |
          echo "$CORP_ROOT_CA_B64" | base64 -d \
            | sudo tee /usr/local/share/ca-certificates/corp-root-ca.crt > /dev/null
          echo "$CORP_INTERMEDIATE_CA_B64" | base64 -d \
            | sudo tee /usr/local/share/ca-certificates/corp-intermediate-ca.crt > /dev/null
          sudo update-ca-certificates

          # Crea un bundle combinato per gli strumenti che richiedono un singolo file CA
          cat /usr/local/share/ca-certificates/corp-*.crt \
            | sudo tee /usr/local/share/ca-certificates/corp-bundle.crt > /dev/null

          echo 'export NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/corp-bundle.crt' \
            | sudo tee /etc/profile.d/node-ca.sh > /dev/null
    ```
  </Accordion>

  <Accordion title="Proxy HTTP/HTTPS">
    Instrada tutto il traffico di rete tramite un proxy aziendale.

    <Accordion title="Segreti richiesti">
      * `CORP_HTTP_PROXY` — URL del proxy HTTP (ad es. `http://proxy.corp.example.com:8080`) - `CORP_HTTPS_PROXY` — URL del proxy HTTPS - `CORP_NO_PROXY` — elenco di host, separati da virgole, da escludere dal proxy (ad es.
        `localhost,127.0.0.1,.corp.example.com`)
    </Accordion>

    ```yaml theme={null}
    initialize:
      - name: Configure system-wide proxy
        run: |
          cat << 'PROXY' | sudo tee /etc/profile.d/proxy.sh > /dev/null
          export http_proxy="$CORP_HTTP_PROXY"
          export https_proxy="$CORP_HTTPS_PROXY"
          export no_proxy="$CORP_NO_PROXY"
          export HTTP_PROXY="$CORP_HTTP_PROXY"
          export HTTPS_PROXY="$CORP_HTTPS_PROXY"
          export NO_PROXY="$CORP_NO_PROXY"
          PROXY
          source /etc/profile.d/proxy.sh

    maintenance:
      - name: Configure git proxy
        run: |
          git config --global http.proxy "$CORP_HTTP_PROXY"
          git config --global https.proxy "$CORP_HTTPS_PROXY"

          # Configura il proxy npm
          npm config set proxy "$CORP_HTTP_PROXY"
          npm config set https-proxy "$CORP_HTTPS_PROXY"
    ```
  </Accordion>

  <Accordion title="Proxy autenticato">
    Se il proxy aziendale richiede l'autenticazione tramite nome utente/password.

    <Accordion title="Segreti richiesti">
      * `PROXY_USER` — Nome utente del proxy - `PROXY_PASS` — Password del proxy - `PROXY_HOST` — hostname e porta del proxy (ad es. `proxy.corp.example.com:8080`) - `CORP_NO_PROXY` — host da escludere dal proxy
    </Accordion>

    ```yaml theme={null}
    initialize:
      - name: Configure authenticated proxy
        run: |
          PROXY_URL="http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}"

          cat << PROXY | sudo tee /etc/profile.d/proxy.sh > /dev/null
          export http_proxy="$PROXY_URL"
          export https_proxy="$PROXY_URL"
          export no_proxy="$CORP_NO_PROXY"
          export HTTP_PROXY="$PROXY_URL"
          export HTTPS_PROXY="$PROXY_URL"
          export NO_PROXY="$CORP_NO_PROXY"
          PROXY
          source /etc/profile.d/proxy.sh

    maintenance:
      - name: Configure git for authenticated proxy
        run: |
          PROXY_URL="http://${PROXY_USER}:${PROXY_PASS}@${PROXY_HOST}"
          git config --global http.proxy "$PROXY_URL"
          git config --global https.proxy "$PROXY_URL"
    ```
  </Accordion>

  <Accordion title="Certificato CA + proxy (combinati)">
    Configurazione combinata per ambienti che richiedono sia una CA aziendale sia un proxy. Questa configurazione è comune negli ambienti enterprise in cui i servizi interni usano certificati privati e tutto il traffico deve passare tramite un proxy.

    <Accordion title="Segreti richiesti">
      * `CORP_ROOT_CA_B64` — certificato CA aziendale codificato in Base64 - `CORP_HTTP_PROXY`, `CORP_HTTPS_PROXY` — URL del proxy - `CORP_NO_PROXY` — host da escludere dal proxy
    </Accordion>

    ```yaml theme={null}
    initialize:
      - name: Install corporate CA certificate
        run: |
          echo "$CORP_ROOT_CA_B64" | base64 -d \
            | sudo tee /usr/local/share/ca-certificates/corp-root-ca.crt > /dev/null
          sudo update-ca-certificates
          echo 'export NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/corp-root-ca.crt' \
            | sudo tee /etc/profile.d/node-ca.sh > /dev/null

      - name: Configure system-wide proxy
        run: |
          cat << 'PROXY' | sudo tee /etc/profile.d/proxy.sh > /dev/null
          export http_proxy="$CORP_HTTP_PROXY"
          export https_proxy="$CORP_HTTPS_PROXY"
          export no_proxy="$CORP_NO_PROXY"
          export HTTP_PROXY="$CORP_HTTP_PROXY"
          export HTTPS_PROXY="$CORP_HTTPS_PROXY"
          export NO_PROXY="$CORP_NO_PROXY"
          PROXY
          source /etc/profile.d/proxy.sh

    maintenance:
      - name: Configure git proxy
        run: |
          git config --global http.proxy "$CORP_HTTP_PROXY"
          git config --global https.proxy "$CORP_HTTPS_PROXY"
    ```
  </Accordion>

  <Accordion title="Connessione VPN">
    I tuoi registry privati, i server Git o altri servizi interni sono raggiungibili solo tramite VPN. Questo modulo deve essere eseguito **prima** degli altri moduli che richiedono l'accesso di rete alle risorse interne.

    <Accordion title="Segreti richiesti">
      **OpenVPN:**

      * `VPN_CONFIG_B64` — file di configurazione OpenVPN (`.ovpn`) codificato in Base64. Genera con: `cat corp.ovpn | base64 -w0`
      * `VPN_AUTH_USER` *(facoltativo)* — nome utente VPN, se la VPN richiede l'autenticazione con nome utente/password
      * `VPN_AUTH_PASS` *(facoltativo)* — password VPN

      **WireGuard:**

      * `WG_CONFIG_B64` — file di configurazione WireGuard codificato in Base64. Genera con: `cat wg0.conf | base64 -w0`
    </Accordion>

    **OpenVPN:**

    ```yaml theme={null}
    initialize:
      - name: Install and configure OpenVPN
        run: |
          sudo DEBIAN_FRONTEND=noninteractive apt-get update -qq
          sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openvpn

          # Scrivi la configurazione VPN
          sudo mkdir -p /etc/openvpn/client
          echo "$VPN_CONFIG_B64" | base64 -d \
            | sudo tee /etc/openvpn/client/corp.conf > /dev/null

          # Se la VPN richiede autenticazione con username/password
          if [ -n "${VPN_AUTH_USER:-}" ] && [ -n "${VPN_AUTH_PASS:-}" ]; then
            printf '%s\n%s\n' "$VPN_AUTH_USER" "$VPN_AUTH_PASS" \
              | sudo tee /etc/openvpn/client/auth.txt > /dev/null
            sudo chmod 600 /etc/openvpn/client/auth.txt
            echo "auth-user-pass /etc/openvpn/client/auth.txt" \
              | sudo tee -a /etc/openvpn/client/corp.conf > /dev/null
          fi

          # Avvia il tunnel VPN
          sudo systemctl daemon-reload
          sudo systemctl enable --now openvpn-client@corp

          # Attendi che il tunnel sia attivo
          for i in $(seq 1 30); do
            if ip link show tun0 >/dev/null 2>&1; then break; fi
            sleep 1
          done
    ```

    **WireGuard:**

    ```yaml theme={null}
    initialize:
      - name: Install and configure WireGuard
        run: |
          sudo DEBIAN_FRONTEND=noninteractive apt-get update -qq
          sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq wireguard-tools

          # Scrivi la configurazione WireGuard
          echo "$WG_CONFIG_B64" | base64 -d \
            | sudo tee /etc/wireguard/wg0.conf > /dev/null
          sudo chmod 600 /etc/wireguard/wg0.conf

          # Avvia il tunnel
          sudo systemctl enable --now wg-quick@wg0
    ```

    <Tip>
      Per maggiori dettagli sulla configurazione della VPN, consulta [Configurazione della VPN](/it/onboard-devin/vpn).
    </Tip>
  </Accordion>

  <Accordion title="Risoluzione DNS personalizzata">
    I tuoi servizi interni utilizzano nomi DNS privati che non possono essere risolti dal DNS pubblico.

    ```yaml theme={null}
    initialize:
      - name: Configure custom DNS resolution
        run: |
          # Aggiungi hostname interni
          cat << 'HOSTS' | sudo tee -a /etc/hosts > /dev/null
          10.0.1.50  nexus.corp.internal
          10.0.1.51  git.corp.internal
          10.0.1.52  artifactory.corp.internal
          HOSTS

          # Facoltativamente configura nameserver personalizzati
          sudo mkdir -p /etc/systemd/resolved.conf.d
          cat << 'DNS' | sudo tee /etc/systemd/resolved.conf.d/corp.conf > /dev/null
          [Resolve]
          DNS=10.0.0.53 10.0.0.54
          Domains=corp.internal
          DNS
          sudo systemctl restart systemd-resolved || true
    ```
  </Accordion>
</AccordionGroup>

<div id="identity-and-security">
  ### Identità e sicurezza
</div>

<AccordionGroup>
  <Accordion title="Firma GPG dei commit">
    La tua organizzazione richiede che tutti i commit Git siano firmati e vuoi che GitHub contrassegni i commit di Devin come **Verified**.

    <Accordion title="Segreti richiesti">
      * `GPG_PRIVATE_KEY_B64` — chiave privata GPG codificata in Base64. Genera con: `gpg --export-secret-keys <key-id> | base64 -w0`
      * `GIT_USER_NAME` — nome autore Git (ad es. `Devin AI`)
      * `GIT_USER_EMAIL` — email autore Git. **Deve corrispondere a un UID della chiave GPG**, altrimenti GitHub non verificherà la firma.
    </Accordion>

    <Note>
      Carica anche la chiave **pubblica** corrispondente nell'account GitHub le cui credenziali Devin usa per eseguire il push (in [GitHub Settings > SSH and GPG keys](https://github.com/settings/keys)). GitHub contrassegna i commit come Verified solo quando la chiave pubblica usata per la firma è registrata nell'account autore del commit.
    </Note>

    ```yaml theme={null}
    initialize:
      - name: Prepare GPG and git signing config
        run: |
          # Consenti a GPG di funzionare senza un TTY
          echo 'export GPG_TTY=$(tty)' | sudo tee -a /etc/profile.d/gpg.sh > /dev/null

    maintenance:
      - name: Import GPG key and configure git signing
        run: |
          echo "$GPG_PRIVATE_KEY_B64" | base64 -d | gpg --batch --import 2>/dev/null

          KEY_ID=$(gpg --list-secret-keys --keyid-format long 2>/dev/null \
            | grep sec | head -1 | awk '{print $2}' | cut -d'/' -f2)

          git config --global user.signingkey "$KEY_ID"
          git config --global commit.gpgsign true
          git config --global tag.gpgsign true
          git config --global gpg.program gpg
    ```
  </Accordion>

  <Accordion title="Identità Git e chiavi SSH">
    Configura l'identità Git e le chiavi SSH di Devin per accedere a server Git privati.

    <Accordion title="Segreti richiesti">
      * `GIT_USER_NAME` — nome autore Git - `GIT_USER_EMAIL` — email autore Git - `SSH_PRIVATE_KEY_B64` — chiave privata SSH codificata in Base64. Genera con: `cat ~/.ssh/id_ed25519 | base64 -w0` -
        `SSH_KNOWN_HOSTS_B64` — voci known\_hosts codificate in Base64. Genera con: `ssh-keyscan git.corp.internal | base64 -w0` - `SSH_CONFIG_B64` *(facoltativo)* — file di configurazione SSH codificato in Base64
    </Accordion>

    ```yaml theme={null}
    initialize:
      - name: Configure git identity
        run: |
          git config --global user.name "$GIT_USER_NAME"
          git config --global user.email "$GIT_USER_EMAIL"

          # Prepara la directory SSH
          mkdir -p ~/.ssh && chmod 700 ~/.ssh

    maintenance:
      - name: Install SSH keys
        run: |
          # Installa la chiave privata SSH (in maintenance così viene ricaricata a ogni sessione)
          echo "$SSH_PRIVATE_KEY_B64" | base64 -d > ~/.ssh/id_ed25519
          chmod 600 ~/.ssh/id_ed25519

          # Aggiungi i known hosts per il tuo server Git
          echo "$SSH_KNOWN_HOSTS_B64" | base64 -d >> ~/.ssh/known_hosts

          # Installa facoltativamente una configurazione SSH personalizzata
          if [ -n "${SSH_CONFIG_B64:-}" ]; then
            echo "$SSH_CONFIG_B64" | base64 -d > ~/.ssh/config
            chmod 600 ~/.ssh/config
          fi
    ```

    <Tip>
      Genera la voce known\_hosts per il tuo server Git con `ssh-keyscan git.corp.internal | base64 -w0`.
    </Tip>
  </Accordion>
</AccordionGroup>

<div id="system-configuration">
  ### Configurazione del sistema
</div>

<AccordionGroup>
  <Accordion title="Pacchetti di sistema">
    Installa pacchetti di sistema che non sono presenti nell'immagine Devin predefinita (ad es. librerie native per l'elaborazione delle immagini o la generazione di PDF).

    ```yaml theme={null}
    initialize:
      - name: Install system packages
        run: |
          sudo apt-get update -qq
          sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq \
            libpq-dev \
            libmagickwand-dev \
            poppler-utils \
            ffmpeg
    ```
  </Accordion>

  <Accordion title="Variabili d'ambiente personalizzate">
    Imposta variabili d'ambiente persistenti da rendere disponibili in ogni sessione.

    L'approccio consigliato è scrivere righe `KEY=VALUE` nel file `$ENVRC`. Le variabili scritte in `$ENVRC` vengono esportate automaticamente per tutti i passaggi successivi e per la sessione di Devin (in modo analogo a `$GITHUB_ENV` di GitHub Actions).

    ```yaml theme={null}
    initialize:
      - name: Set custom environment variables
        run: |
          echo "CORPORATE_ENV=production" >> $ENVRC
          echo "DEFAULT_REGION=us-east-1" >> $ENVRC
          echo "MAX_RETRIES=3" >> $ENVRC
    ```

    <Tip>
      Puoi anche scrivere le variabili d'ambiente negli script in `/etc/profile.d/` per renderle disponibili a livello di sistema:

      ```bash theme={null}
      cat << 'ENVVARS' | sudo tee /etc/profile.d/custom-env.sh > /dev/null
      export CORPORATE_ENV=production
      export DEFAULT_REGION=us-east-1
      ENVVARS
      ```

      Entrambi gli approcci funzionano. `$ENVRC` è più semplice ed è consigliato nella maggior parte dei casi.
    </Tip>
  </Accordion>

  <Accordion title="Impostazioni locali e fuso orario">
    Le immagini di base predefinite potrebbero avere impostazioni del locale non corrette. Configura il locale e il fuso orario per evitare avvisi da strumenti di build, Java, Python e Git.

    ```yaml theme={null}
    initialize:
      - name: Configure locale and timezone
        run: |
          sudo DEBIAN_FRONTEND=noninteractive apt-get update -qq
          sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq locales

          # Genera e imposta il locale
          sudo sed -i 's/^# *en_US.UTF-8/en_US.UTF-8/' /etc/locale.gen
          sudo locale-gen
          sudo update-locale LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8

          cat << 'LOCALE' | sudo tee /etc/profile.d/locale.sh > /dev/null
          export LANG="en_US.UTF-8"
          export LC_ALL="en_US.UTF-8"
          LOCALE

          # Imposta il fuso orario
          sudo timedatectl set-timezone UTC 2>/dev/null || \
            sudo ln -sfn /usr/share/zoneinfo/UTC /etc/localtime
    ```
  </Accordion>

  <Accordion title="Limiti di risorse (ulimits)">
    Le build Java, Gradle e Node.js raggiungono spesso il limite predefinito di 1024 file aperti. Aumentalo per evitare errori di build.

    ```yaml theme={null}
    initialize:
      - name: Raise resource limits
        run: |
          cat << 'LIMITS' | sudo tee /etc/security/limits.d/99-devin.conf > /dev/null
          *    soft    nofile    65536
          *    hard    nofile    65536
          *    soft    nproc     65536
          *    hard    nproc     65536
          LIMITS

          # Imposta anche il massimo del kernel
          echo "fs.file-max = 65536" | sudo tee /etc/sysctl.d/99-devin-filemax.conf > /dev/null
          sudo sysctl -p /etc/sysctl.d/99-devin-filemax.conf 2>/dev/null || true
    ```
  </Accordion>

  <Accordion title="Sostituzione del mirror di APT">
    In ambienti air-gapped o soggetti a restrizioni, sostituisci i repository APT predefiniti di Ubuntu con un mirror interno.

    <Accordion title="Segreti richiesti">- `APT_MIRROR_URL` — URL del tuo mirror APT interno (ad es. `https://artifactory.example.com/artifactory/ubuntu-remote`)</Accordion>

    ```yaml theme={null}
    initialize:
      - name: Replace APT sources with internal mirror
        run: |
          # Backup delle sorgenti originali
          sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak

          # Sostituisci tutti i mirror Ubuntu con il mirror interno
          sudo sed -i "s|http://archive.ubuntu.com/ubuntu|$APT_MIRROR_URL|g" /etc/apt/sources.list
          sudo sed -i "s|http://security.ubuntu.com/ubuntu|$APT_MIRROR_URL|g" /etc/apt/sources.list

          sudo apt-get update -qq
    ```

    <Tip>
      Pattern di URL comuni per i mirror APT:

      * **Artifactory:** `https://artifactory.example.com/artifactory/ubuntu-remote`
      * **Nexus:** `https://nexus.example.com/repository/ubuntu-proxy`
    </Tip>
  </Accordion>
</AccordionGroup>

***

<div id="advanced-patterns">
  ## Pattern avanzati
</div>

<AccordionGroup>
  <Accordion title="Variabili di ambiente con direnv">
    L'ambiente di base di Devin include [direnv](https://direnv.net/). Usa `initialize` per creare i file `.envrc`. Direnv li carica automaticamente.

    ```yaml theme={null}
    initialize: |
      cat <<'EOF' > .envrc
      export DATABASE_URL=postgresql://localhost:5432/myapp_dev
      export REDIS_URL=redis://localhost:6379
      export APP_ENV=development
      EOF

    maintenance: |
      direnv allow .
    ```

    <Info>
      direnv è già configurato nella shell di Devin, quindi le variabili di `.envrc` vengono caricate automaticamente. Non serve eseguire il source manualmente.
    </Info>

    <Tip>
      Per le variabili d'ambiente **sensibili** (API key, token, password del database), usa i [segreti del repo](/it/product-guides/secrets) invece dei file `.envrc`. I segreti del repo sono archiviati in modo sicuro e vengono iniettati all'avvio della sessione. Non compaiono mai nel blueprint o nello snapshot.
    </Tip>
  </Accordion>

  <Accordion title="Cambio della versione di Node per singola repo">
    Usa nvm (preinstallato) per cambiare versione di Node.js per ciascun repository tramite `.nvmrc`.

    ```yaml theme={null}
    initialize: |
      nvm install 18
      nvm install 20
      nvm install 22

    maintenance: |
      nvm use
    ```

    <Info>
      `nvm use` legge `.nvmrc` dalla directory radice della repo. Assicurati che il repository ne abbia uno (ad es., contenente `20`).
    </Info>
  </Accordion>

  <Accordion title="Autenticazione nel browser (Playwright)">
    Devin mette a disposizione un browser Chrome con un endpoint CDP su `localhost:29229` **durante le sessioni**. Usa script Playwright per automatizzare il login nel browser.

    <Warning>Il browser è disponibile solo durante le sessioni, non nelle build snapshot. Installa Playwright in `initialize` e conserva gli script di login nella tua repo.</Warning>

    ```yaml theme={null}
    initialize: |
      pip install playwright
      playwright install chromium

    maintenance: |
      npm install

    knowledge:
      - name: browser-auth
        contents: |
          This project requires browser authentication.
          Run the login script before interacting with the app:
          python scripts/login.py

          Devin's Chrome browser is accessible via CDP at:
          http://localhost:29229
    ```

    Esempio di script di accesso (`scripts/login.py`):

    ```python theme={null}
    from playwright.sync_api import sync_playwright
    import os

    with sync_playwright() as p:
        browser = p.chromium.connect_over_cdp("http://localhost:29229")
        context = browser.contexts[0]
        page = context.pages[0] if context.pages else context.new_page()

        page.goto("https://internal-tool.example.com/login")
        page.fill("#username", os.environ["TOOL_USERNAME"])
        page.fill("#password", os.environ["TOOL_PASSWORD"])
        page.click('button[type="submit"]')
        page.wait_for_url("**/dashboard")
    ```

    <Warning>
      Conserva le credenziali di accesso come secrets, non nel codice sorgente. Per un'autenticazione a lungo termine, esegui il commit degli script di accesso in `.agents/skills/` in modo che Devin possa riautenticarsi automaticamente.
    </Warning>
  </Accordion>

  <Accordion title="Strumenti di sistema personalizzati e PATH">
    Installa pacchetti di sistema, binari personalizzati e configura il PATH in `initialize`.

    ```yaml theme={null}
    initialize:
      - name: Install system packages
        run: |
          apt-get update
          apt-get install -y \
            jq \
            ripgrep \
            fd-find \
            protobuf-compiler \
            libssl-dev

      - name: Install custom CLI tool
        run: |
          curl -L https://github.com/example/tool/releases/download/v1.0/tool-linux-amd64 \
            -o /usr/local/bin/mytool
          chmod +x /usr/local/bin/mytool

      - name: Add custom bin directory to PATH
        run: |
          mkdir -p ~/bin
          echo 'export PATH="$HOME/bin:$PATH"' >> ~/.bashrc

    knowledge:
      - name: tools
        contents: |
          Custom tools available:
          - mytool: installed at /usr/local/bin/mytool
          - Additional binaries can be placed in ~/bin
    ```
  </Accordion>

  <Accordion title="GitHub Actions per configurare gli strumenti">
    Devin supporta l'esecuzione diretta nei blueprint di GitHub Actions basate su Node.js. Questo è utile per installare versioni specifiche degli strumenti tramite le stesse azioni usate dalla tua CI.

    ```yaml theme={null}
    initialize:
      - name: "Install Node.js 20"
        uses: github.com/actions/setup-node@v4
        with:
          node-version: "20"

      - name: "Install Python 3.12"
        uses: github.com/actions/setup-python@v5
        with:
          python-version: "3.12"

      - name: "Install Go 1.22"
        uses: github.com/actions/setup-go@v5
        with:
          go-version: "1.22"

      - name: "Install Java 21"
        uses: github.com/actions/setup-java@v4
        with:
          java-version: "21"
          distribution: "temurin"

      - name: "Install Gradle"
        uses: github.com/gradle/actions/setup-gradle@v4

      - name: "Install Ruby 3.3"
        uses: github.com/ruby/setup-ruby@v1
        with:
          ruby-version: "3.3"

      - name: "Install additional tools"
        run: |
          pip install uv
          npm install -g pnpm turbo
          go install golang.org/x/tools/gopls@latest

    maintenance: |
      echo "All runtimes are available:"
      node --version
      python --version
      go version
      java --version
    ```

    <Info>
      Azioni come `setup-node` e `setup-python` modificano il PATH e le variabili d'ambiente. I binari installati da un'azione sono disponibili in tutti i passaggi successivi e in `maintenance`. Sono supportate solo le GitHub Actions **basate su Node.js**. Le azioni composite e quelle basate su Docker non sono supportate.
    </Info>

    <Tip>
      Non servono GitHub Actions per la configurazione di base degli strumenti. I comandi shell diretti (`nvm install 20`, `curl ... | sh`, `apt-get install`) funzionano altrettanto bene e spesso sono più semplici. Le GitHub Actions sono particolarmente utili quando vuoi replicare esattamente la configurazione della tua CI o sfruttare la comodità di azioni come `setup-java`, che gestiscono più distribuzioni.
    </Tip>
  </Accordion>

  <Accordion title="Proxy inverso HTTPS locale per più app">
    Esegui più servizi dietro hostname dall'aspetto realistico su HTTPS, come `app.example.com`, `api.example.com` e `admin.example.com`. Installa un singolo proxy inverso in `initialize` e instrada ogni hostname verso una porta upstream locale diversa.

    [Caddy](https://caddyserver.com/) gestisce il routing e il TLS locale in un unico strumento. Un Caddyfile associa ogni hostname a un upstream e `tls internal` emette automaticamente un certificato attendibile per ciascun hostname dalla CA integrata di Caddy. `caddy trust` installa la root di quella CA nell'archivio di attendibilità del sistema e, aggiungendo la stessa root al database NSS, il browser la accetterà.

    Carica il Caddyfile tramite la sezione **File allegati** dell'editor del blueprint; sarà quindi disponibile come `$FILE_CADDYFILE`.

    ```caddyfile Caddyfile theme={null}
    app.example.com {
      tls internal
      reverse_proxy 127.0.0.1:3000
    }

    api.example.com {
      tls internal
      reverse_proxy 127.0.0.1:3001
    }

    admin.example.com {
      tls internal
      reverse_proxy 127.0.0.1:3002
    }
    ```

    ```yaml theme={null}
    initialize:
      - name: Install Caddy and NSS tools
        run: |
          sudo apt-get install -y debian-keyring debian-archive-keyring \
            apt-transport-https curl libnss3-tools
          curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
            | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
          curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
            | sudo tee /etc/apt/sources.list.d/caddy-stable.list
          sudo apt-get update -qq
          sudo apt-get install -y caddy

      - name: Install Caddyfile, hosts entries, and trust internal CA
        run: |
          sudo install -m 0644 "$FILE_CADDYFILE" /etc/caddy/Caddyfile

          for host in app.example.com api.example.com admin.example.com; do
            grep -q " $host$" /etc/hosts \
              || echo "127.0.0.1 $host" | sudo tee -a /etc/hosts > /dev/null
          done

          sudo systemctl enable --now caddy
          sudo caddy trust

          mkdir -p ~/.pki/nssdb
          [ -f ~/.pki/nssdb/cert9.db ] \
            || certutil -d sql:$HOME/.pki/nssdb -N --empty-password

          CADDY_ROOT=/var/lib/caddy/.local/share/caddy/pki/authorities/local/root.crt
          for _ in $(seq 1 30); do
            sudo test -f "$CADDY_ROOT" && break
            sleep 1
          done

          if sudo test -f "$CADDY_ROOT" \
             && ! certutil -d sql:$HOME/.pki/nssdb -L | grep -q "Caddy Local Authority"; then
            sudo install -o "$USER" -m 0644 "$CADDY_ROOT" /tmp/caddy-root.crt
            certutil -d sql:$HOME/.pki/nssdb -A -t "C,," \
              -n "Caddy Local Authority" -i /tmp/caddy-root.crt
            rm -f /tmp/caddy-root.crt
          fi
    ```

    <Info>
      Il loop di `/etc/hosts` è ciò che consente a `app.example.com` di risolversi in `127.0.0.1` all'interno della sessione. Aggiungi una voce per ogni hostname che inserisci nel Caddyfile.
    </Info>

    <Tip>
      Per aggiungere un servizio, aggiungi un blocco di tre righe al Caddyfile e una voce al loop di `/etc/hosts`, quindi apri il relativo hostname tramite HTTPS. Caddy genera un certificato alla prima richiesta, quindi non è necessario generare certificati separati per ogni app.
    </Tip>
  </Accordion>
</AccordionGroup>

***

<div id="full-stack-examples">
  ## Esempi full-stack
</div>

Questi esempi mostrano come si combinano le configurazioni Enterprise e quelle a livello di org. In pratica, le divideresti tra diversi ambiti. Qui sono riunite a scopo di riferimento.

<AccordionGroup>
  <Accordion title="Stack Enterprise completo (Artifactory)">
    Un ambiente enterprise completo: certificato CA aziendale, proxy, Java (Maven), Python (pip/uv), Node.js (npm) e Docker, tutti puntati a una singola istanza di Artifactory.

    <Accordion title="Segreti richiesti">
      **Rete e attendibilità (per l'intero account):**

      * `CORP_ROOT_CA_B64` — certificato CA aziendale codificato in Base64
      * `CORP_HTTP_PROXY` — URL del proxy HTTP
      * `CORP_HTTPS_PROXY` — URL del proxy HTTPS
      * `CORP_NO_PROXY` — host da escludere dal proxy

      **Credenziali del registry (per l'intera org):**

      * `ARTIFACTORY_USER` — nome utente Artifactory
      * `ARTIFACTORY_TOKEN` — token API o password di Artifactory
      * `ARTIFACTORY_MAVEN_URL` — URL del repository Maven (ad es., `https://artifactory.example.com/artifactory/maven-virtual`)
      * `ARTIFACTORY_PYPI_URL` — URL del repository PyPI (ad es., `https://user:token@artifactory.example.com/artifactory/api/pypi/pypi-virtual/simple`)
      * `ARTIFACTORY_NPM_URL` — URL del repository npm (ad es., `https://artifactory.example.com/artifactory/api/npm/npm-virtual`)
      * `ARTIFACTORY_DOCKER_URL` — URL del registry Docker (ad es., `artifactory.example.com`)
    </Accordion>

    In genere questo verrebbe suddiviso in tre ambiti:

    * **A livello di account (`initialize`):** Certificato e proxy
    * **Org-wide (`initialize`):** Installazione del runtime del linguaggio
    * **A livello di org (`maintenance`):** credenziali del registry (aggiornate durante le build, rese disponibili all'Agent all'avvio della sessione)

    Di seguito il codice completo per riferimento:

    ```yaml theme={null}
    initialize:
      # ── Account-wide: rete e attendibilità ──────────────────────────────────────

      - name: Install corporate CA certificate
        run: |
          echo "$CORP_ROOT_CA_B64" | base64 -d \
            | sudo tee /usr/local/share/ca-certificates/corp-root-ca.crt > /dev/null
          sudo update-ca-certificates
          echo 'export NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/corp-root-ca.crt' \
            | sudo tee /etc/profile.d/node-ca.sh > /dev/null

      - name: Configure system-wide proxy
        run: |
          cat << 'PROXY' | sudo tee /etc/profile.d/proxy.sh > /dev/null
          export http_proxy="$CORP_HTTP_PROXY"
          export https_proxy="$CORP_HTTPS_PROXY"
          export no_proxy="$CORP_NO_PROXY"
          export HTTP_PROXY="$CORP_HTTP_PROXY"
          export HTTPS_PROXY="$CORP_HTTPS_PROXY"
          export NO_PROXY="$CORP_NO_PROXY"
          PROXY
          source /etc/profile.d/proxy.sh

      # ── Org-wide: language runtimes ──────────────────────────────────────────

      - name: Install JDK 17 + Maven
        run: |
          sudo apt-get update -qq
          sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-17-jdk-headless
          echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' \
            | sudo tee /etc/profile.d/java.sh > /dev/null

          MAVEN_VERSION=3.9.9
          curl -fsSL "https://archive.apache.org/dist/maven/maven-3/${MAVEN_VERSION}/binaries/apache-maven-${MAVEN_VERSION}-bin.tar.gz" \
            | sudo tar -xz -C /opt
          sudo ln -sf /opt/apache-maven-${MAVEN_VERSION}/bin/mvn /usr/local/bin/mvn

      - name: Install uv
        run: curl -LsSf https://astral.sh/uv/install.sh | sh

    maintenance:
      # ── Account-wide: git proxy (aggiornato ad ogni session) ───────────────────

      - name: Configure git proxy
        run: |
          git config --global http.proxy "$CORP_HTTP_PROXY"
          git config --global https.proxy "$CORP_HTTPS_PROXY"

      # ── Org-wide: registry credentials (aggiornate ad ogni session) ──────────────

      - name: Configure Maven → Artifactory
        run: |
          mkdir -p ~/.m2
          cat > ~/.m2/settings.xml << EOF
          <settings>
            <mirrors>
              <mirror>
                <id>artifactory</id>
                <mirrorOf>*</mirrorOf>
                <url>$ARTIFACTORY_MAVEN_URL</url>
              </mirror>
            </mirrors>
            <servers>
              <server>
                <id>artifactory</id>
                <username>$ARTIFACTORY_USER</username>
                <password>$ARTIFACTORY_TOKEN</password>
              </server>
            </servers>
          </settings>
          EOF

      - name: Configure pip/uv → Artifactory PyPI
        run: |
          mkdir -p ~/.config/pip
          cat > ~/.config/pip/pip.conf << EOF
          [global]
          index-url = $ARTIFACTORY_PYPI_URL
          trusted-host = $(echo "$ARTIFACTORY_PYPI_URL" | sed 's|https\?://||;s|/.*||')
          EOF

          echo "export UV_INDEX_URL=$ARTIFACTORY_PYPI_URL" \
            | sudo tee /etc/profile.d/uv-registry.sh > /dev/null

      - name: Configure npm → Artifactory
        run: |
          npm config set registry "$ARTIFACTORY_NPM_URL"
          REGISTRY_HOST=$(echo "$ARTIFACTORY_NPM_URL" | sed 's|https\?://||;s|/.*||')
          npm config set "//${REGISTRY_HOST}/:_authToken" "$ARTIFACTORY_TOKEN"

      - name: Configure Docker → Artifactory
        run: |
          echo "$ARTIFACTORY_TOKEN" | docker login "$ARTIFACTORY_DOCKER_URL" \
            --username "$ARTIFACTORY_USER" \
            --password-stdin
    ```

    <Info>
      In questo esempio, tutti i registry puntano alla stessa istanza di Artifactory, ma utilizzano percorsi URL diversi. Ogni ecosistema di pacchetti ha il proprio formato di endpoint. Gli URL di Maven, PyPI, npm e Docker sono tutti diversi, anche per lo stesso registry.
    </Info>
  </Accordion>

  <Accordion title="Multilingua con registry diversi">
    Quando linguaggi diversi usano registry privati diversi (ad es. Maven da Nexus, npm da GitHub Packages, Python da Artifactory).

    <Accordion title="Segreti richiesti">
      * `NEXUS_MAVEN_URL` — URL del repository Maven di Nexus
      * `NEXUS_USER` — nome utente di Nexus
      * `NEXUS_PASS` — password di Nexus
      * `GITHUB_PACKAGES_TOKEN` — token di accesso personale di GitHub con ambito `read:packages`
      * `ARTIFACTORY_USER` — nome utente di Artifactory
      * `ARTIFACTORY_TOKEN` — token API di Artifactory
      * `GIT_TOKEN` — token di accesso personale per i moduli Go privati
    </Accordion>

    ```yaml theme={null}
    maintenance:
      # Maven → Nexus
      - name: Configure Maven → Nexus
        run: |
          mkdir -p ~/.m2
          cat > ~/.m2/settings.xml << EOF
          <settings>
            <mirrors>
              <mirror>
                <id>nexus</id>
                <mirrorOf>*</mirrorOf>
                <url>$NEXUS_MAVEN_URL</url>
              </mirror>
            </mirrors>
            <servers>
              <server>
                <id>nexus</id>
                <username>$NEXUS_USER</username>
                <password>$NEXUS_PASS</password>
              </server>
            </servers>
          </settings>
          EOF

      # npm → GitHub Packages (con ambito)
      - name: Configure npm → GitHub Packages
        run: |
          npm config set @myorg:registry https://npm.pkg.github.com
          npm config set //npm.pkg.github.com/:_authToken $GITHUB_PACKAGES_TOKEN

      # Python → Artifactory
      - name: Configure pip → Artifactory
        run: |
          mkdir -p ~/.config/pip
          cat > ~/.config/pip/pip.conf << EOF
          [global]
          index-url = https://$ARTIFACTORY_USER:$ARTIFACTORY_TOKEN@artifactory.example.com/artifactory/api/pypi/pypi-virtual/simple
          EOF

      # Go → moduli privati tramite git
      - name: Configure Go private modules
        run: |
          git config --global url."https://$GIT_TOKEN@github.com/myorg/".insteadOf "https://github.com/myorg/"
    ```
  </Accordion>

  <Accordion title="Ambiente isolato dalla rete con mirror privati">
    In un ambiente completamente air-gapped, Devin non può accedere ad alcun URL pubblico. Tutti gli strumenti, i runtime e i pacchetti devono provenire da mirror interni.

    <Accordion title="Segreti richiesti">
      \*\* Certificati: \*\*

      * `CORP_ROOT_CA_B64` — certificato CA aziendale codificato in Base64

      **Accesso ai mirror:**

      * `APT_MIRROR_URL` — URL del mirror APT interno di Ubuntu
      * `MIRROR_USER` — nome utente per l'autenticazione al mirror
      * `MIRROR_PASS` — password per l'autenticazione al mirror
      * `JDK_TARBALL_URL` — URL da cui scaricare il tarball JDK dal mirror interno
      * `NODE_TARBALL_URL` — URL da cui scaricare il tarball Node.js dal mirror interno

      **Registry dei pacchetti:**

      * `INTERNAL_MAMEN_URL` — URL del registry Maven interno
      * `INTERNAL_NPM_URL` — URL del registry npm interno
      * `INTERNAL_PYPI_URL` — URL del registry PyPI interno
    </Accordion>

    ```yaml theme={null}
    initialize:
      - name: Install corporate CA certificate
        run: |
          echo "$CORP_ROOT_CA_B64" | base64 -d \
            | sudo tee /usr/local/share/ca-certificates/corp-root-ca.crt > /dev/null
          sudo update-ca-certificates

      - name: Replace apt sources with internal mirror
        run: |
          sudo sed -i "s|http://archive.ubuntu.com/ubuntu|$APT_MIRROR_URL|g" /etc/apt/sources.list
          sudo sed -i "s|http://security.ubuntu.com/ubuntu|$APT_MIRROR_URL|g" /etc/apt/sources.list
          sudo apt-get update -qq

      - name: Install JDK from internal mirror
        run: |
          # Scarica il tarball JDK dall'archivio artefatti interno
          curl -fsSL -u "$MIRROR_USER:$MIRROR_PASS" "$JDK_TARBALL_URL" \
            | sudo tar -xz -C /usr/local
          sudo ln -sf /usr/local/jdk-17.*/bin/java /usr/local/bin/java
          sudo ln -sf /usr/local/jdk-17.*/bin/javac /usr/local/bin/javac
          echo "export JAVA_HOME=$(ls -d /usr/local/jdk-17.*)" \
            | sudo tee /etc/profile.d/java.sh > /dev/null

      - name: Install Node.js from internal mirror
        run: |
          curl -fsSL -u "$MIRROR_USER:$MIRROR_PASS" "$NODE_TARBALL_URL" \
            | sudo tar -xz -C /usr/local --strip-components=1

    maintenance:
      - name: Configure all package managers for internal registry
        run: |
          # Maven
          mkdir -p ~/.m2
          cat > ~/.m2/settings.xml << EOF
          <settings>
            <mirrors>
              <mirror>
                <id>internal</id>
                <mirrorOf>*</mirrorOf>
                <url>$INTERNAL_MAVEN_URL</url>
              </mirror>
            </mirrors>
            <servers>
              <server>
                <id>internal</id>
                <username>$MIRROR_USER</username>
                <password>$MIRROR_PASS</password>
              </server>
            </servers>
          </settings>
          EOF

          # npm
          npm config set registry "$INTERNAL_NPM_URL"

          # pip
          mkdir -p ~/.config/pip
          cat > ~/.config/pip/pip.conf << EOF
          [global]
          index-url = $INTERNAL_PYPI_URL
          EOF
    ```

    <Warning>
      Neglii ambienti air-gapped, tutti gli strumenti necessari a Devin (runtime dei linguaggi di programmazione, strumenti CLI, ecc.) devono essere disponibili sui vostre mirror interni. I registry pubblici e i siti di download non sono raggiungibili.
    </Warning>
  </Accordion>

  <Accordion title="VPN + certificati + proxy + linguaggi">
    Una configurazione Enterprise completa che combina connettività VPN con certificati, proxy e supporto multilingua. Questo è l'ordine delle operazioni consigliato.

    <Accordion title="Segreti richiesti">
      **VPN:**

      * `VPN_CONFIG_B64` — file di configurazione OpenVPN codificato in Base64

      **Rete & attendibilità:**

      * `CORP_ROOT_CA_B64` — certificato CA aziendale codificato in Base64
      * `CORP_HTTP_PROXY` — URL del proxy HTTP
      * `CORP_HTTPS_PROXY` — URL del proxy HTTPS
      * `CORP_NO_PROXY` — host da escludere dal proxy

      **Credenziali del registry:**

      * `MAVEN_REGISTRY_URL` — URL del registry Maven
      * `NPM_REGISTRY_URL` — URL del registry npm
      * `PYPI_REGISTRY_HOST` — hostname del registry PyPI
      * `REGISTRY_USER` — nome utente del registry (per Maven e pip)
      * `REGISTRY_PASS` — password del registry (per Maven e pip)
      * `REGISTRY_TOKEN` — token di autenticazione per npm
    </Accordion>

    ```yaml theme={null}
    initialize:
      # 1. VPN — deve essere il primo affinché le risorse interne siano raggiungibili
      - name: Establish VPN connection
        run: |
          sudo DEBIAN_FRONTEND=noninteractive apt-get update -qq
          sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openvpn
          sudo mkdir -p /etc/openvpn/client
          echo "$VPN_CONFIG_B64" | base64 -d \
            | sudo tee /etc/openvpn/client/corp.conf > /dev/null
          sudo systemctl daemon-reload
          sudo systemctl enable --now openvpn-client@corp
          for i in $(seq 1 30); do
            if ip link show tun0 >/dev/null 2>&1; then break; fi
            sleep 1
          done

      # 2. DNS — risolve gli hostname interni
      - name: Configure DNS
        run: |
          sudo mkdir -p /etc/systemd/resolved.conf.d
          cat << 'DNS' | sudo tee /etc/systemd/resolved.conf.d/corp.conf > /dev/null
          [Resolve]
          DNS=10.0.0.53
          Domains=corp.internal
          DNS
          sudo systemctl restart systemd-resolved || true

      # 3. Certificati — attendibilità delle CA interne
      - name: Install CA certificate
        run: |
          echo "$CORP_ROOT_CA_B64" | base64 -d \
            | sudo tee /usr/local/share/ca-certificates/corp-root-ca.crt > /dev/null
          sudo update-ca-certificates
          echo 'export NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/corp-root-ca.crt' \
            | sudo tee /etc/profile.d/node-ca.sh > /dev/null

      # 4. Proxy — instrada il traffico attraverso il proxy aziendale
      - name: Configure proxy
        run: |
          cat << 'PROXY' | sudo tee /etc/profile.d/proxy.sh > /dev/null
          export http_proxy="$CORP_HTTP_PROXY"
          export https_proxy="$CORP_HTTPS_PROXY"
          export no_proxy="$CORP_NO_PROXY"
          export HTTP_PROXY="$CORP_HTTP_PROXY"
          export HTTPS_PROXY="$CORP_HTTPS_PROXY"
          export NO_PROXY="$CORP_NO_PROXY"
          PROXY
          source /etc/profile.d/proxy.sh

      # 5. Language runtimes
      - name: Install JDK 17
        run: |
          sudo DEBIAN_FRONTEND=noninteractive apt-get install -y -qq openjdk-17-jdk-headless
          echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' \
            | sudo tee /etc/profile.d/java.sh > /dev/null

      - name: Install Node.js tooling
        run: npm install -g pnpm

      - name: Install uv
        run: curl -LsSf https://astral.sh/uv/install.sh | sh

    maintenance:
      - name: Configure git proxy
        run: |
          git config --global http.proxy "$CORP_HTTP_PROXY"
          git config --global https.proxy "$CORP_HTTPS_PROXY"

      - name: Configure Maven
        run: |
          mkdir -p ~/.m2
          cat > ~/.m2/settings.xml << EOF
          <settings>
            <mirrors>
              <mirror>
                <id>corp</id>
                <mirrorOf>*</mirrorOf>
                <url>$MAVEN_REGISTRY_URL</url>
              </mirror>
            </mirrors>
            <servers>
              <server>
                <id>corp</id>
                <username>$REGISTRY_USER</username>
                <password>$REGISTRY_PASS</password>
              </server>
            </servers>
          </settings>
          EOF

      - name: Configure npm
        run: |
          npm config set registry "$NPM_REGISTRY_URL"
          NPM_HOST=$(echo "$NPM_REGISTRY_URL" | sed 's|https\?://||;s|/.*||')
          npm config set "//${NPM_HOST}/:_authToken" "$REGISTRY_TOKEN"

      - name: Configure pip/uv
        run: |
          mkdir -p ~/.config/pip
          cat > ~/.config/pip/pip.conf << EOF
          [global]
          index-url = https://$REGISTRY_USER:$REGISTRY_PASS@${PYPI_REGISTRY_HOST}/simple
          EOF
          echo "export UV_INDEX_URL=https://$REGISTRY_USER:$REGISTRY_PASS@${PYPI_REGISTRY_HOST}/simple" \
            | sudo tee /etc/profile.d/uv-registry.sh > /dev/null
    ```

    <Info>
      \*\*L'ordine dei passaggi `initialize` è importante.\*\*La VPN deve venire per prima (in modo che gli host interni siano raggiungibili), poi il DNS (in modo che i nomi vengano risolti), poi i certificati (in modo che HTTPS funzioni), poi il proxy (in modo che il traffico venga instradato correttamente) e infine i runtime dei linguaggi (che potrebbero scaricare da mirror interni).
    </Info>
  </Accordion>
</AccordionGroup>

***

<div id="tips-for-writing-good-blueprints">
  ## Suggerimenti per scrivere blueprint efficaci
</div>

* **Prova prima i comandi in una sessione.** Esegui i comandi manualmente in una sessione di Devin prima di aggiungerli al blueprint. È più veloce che aspettare un ciclo di build completo.
* **Usa `initialize` per gli strumenti da installare una sola volta, `maintenance` per le dipendenze.** Tutto ciò che richiede minuti per essere installato (compilatori, binari di grandi dimensioni, strumenti globali) va in `initialize`. I comandi rapidi per le dipendenze (`npm install`, `uv sync`) vanno in `maintenance`.
* **Mantieni rapidi i comandi `maintenance`.** Cerca di restare sotto i 2 minuti. Vengono eseguiti durante le build e vengono mostrati all'agente all'inizio della sessione.
* **Usa `$ENVRC` per le variabili d'ambiente.** Non scrivere in `.bashrc` o `.profile`. `$ENVRC` è il meccanismo supportato per impostare variabili tra passaggi e sessioni.
* **Assegna un nome ai passaggi.** La forma estesa con i campi `name` rende molto più semplice individuare gli errori nei log di build.
* **Usa le subshell per i monorepo.** `(cd packages/foo && npm install)` viene eseguito in una subshell, così i passaggi successivi non risentono del cambio di directory.
* **Usa `npm install`, non `npm ci`.** `npm ci` elimina `node_modules` e reinstalla tutto da zero, rallentando `maintenance`.
* **Usa i secrets del repo per i valori sensibili.** Configurali nella scheda **Secrets** dell'editor del blueprint del repository invece di inserirli direttamente nei blueprint.

Per i dettagli sulla sintassi, consulta il [riferimento del blueprint](/it/onboard-devin/environment/blueprint-reference). Per risolvere gli errori di build, consulta [Configurazione dichiarativa > Risoluzione dei problemi](/it/onboard-devin/environment/blueprints#troubleshooting-builds).
