

Les traductions sont fournies par des outils de traduction automatique. En cas de conflit entre le contenu d'une traduction et celui de la version originale en anglais, la version anglaise prévaudra.

# Bloquer les packages sur l'âge de la version
<a name="package-version-age-gating"></a>

**Important**  
Le blocage par ancienneté des versions ne protège pas contre les vulnérabilités découvertes dans les versions existantes qui ont déjà dépassé la période de quarantaine. CodeArtifact À utiliser avec Amazon Inspector pour analyser les vulnérabilités des packages établis.

Lorsqu'une version de package est publiée dans un registre public, le registre enregistre l'horodatage de publication. CodeArtifact préserve ces horodatages initiaux en amont lorsqu'il met en cache des packages provenant de connexions externes. Vous pouvez lire ces horodatages dans votre CI/CD pipeline et rejeter les versions publiées trop récemment.

La plupart des paquets malveillants sont détectés et supprimés dans les heures qui suivent leur publication. Une période de quarantaine de 3 à 7 jours bloque la majorité des attaques liées à la chaîne d'approvisionnement, notamment la confusion liée aux dépendances, le piratage du compte du responsable et le typosquatting.

**Note**  
Les exemples présentés dans cette rubrique interrogent l'URL du CodeArtifact référentiel, qui est le même point de terminaison que votre gestionnaire de packages utilise pour télécharger des packages. Toutes les demandes nécessitent une authentification. Passez un jeton CodeArtifact d'autorisation valide dans l'`Authorization: Bearer`en-tête. Pour obtenir un jeton, exécutez `aws codeartifact get-authorization-token` (voir l' CI/CD exemple plus loin dans cette rubrique pour l'invocation complète avec `--domain` et`--domain-owner`).  
N'utilisez pas le `publishedTime` champ renvoyé par `aws codeartifact describe-package-version` pour la détermination de l'âge. Ce champ est renseigné au moment de l'ingestion. Pour les enregistrements dont l'heure de publication initiale en amont n'a pas été capturée (y compris les packages ingérés avant l'introduction de la capture de l'horodatage par artefact et certains chemins d'ingestion), elle revient silencieusement à l'heure de dernière mise à jour de l'enregistrement. La réponse de l'API n'indique pas laquelle des deux valeurs vous êtes en train de lire. Vous ne pouvez donc pas vous y fier comme date de publication en amont. Utilisez plutôt les champs par format décrits dans cette rubrique.

Les détails par format diffèrent, mais le schéma de sélection est le même pour tous les formats : lisez l'horodatage de publication en amont pour chaque version résolue, comparez-le à votre limite de quarantaine (l'heure actuelle moins la fenêtre que vous avez choisie) et faites échouer la compilation si une version est plus récente que la date limite. Si vous utilisez plusieurs formats de package, vous devez appliquer le même modèle avec le champ spécifique au format illustré ci-dessous.

## npm
<a name="package-version-age-gating-npm"></a>

CodeArtifact renvoie l'horodatage de publication original de npmjs.org pour chaque version dans le champ npm packument. `time` De nombreux gestionnaires de packages et outils de sécurité lisent ce champ de manière native. Il s'agit notamment de l'`npmMinimalAgeGate`option Yarn 4, du `minimumReleaseAge` paramètre Renovate et du `minimumReleaseAge` paramètre pnpm, qui fonctionnent tous CodeArtifact sans modification.

**Requête :**

```
curl -H "Authorization: Bearer $CODEARTIFACT_AUTH_TOKEN" \
  https://my-domain-111122223333.d.codeartifact.us-east-1.amazonaws.com/npm/my-repo/axios
```

**Réponse (abrégée) :**

```
{
  "name": "axios",
  "time": {
    "1.6.0": "2023-10-26T21:15:55.685Z",
    "1.6.5": "2024-01-05T19:52:15.051Z",
    "1.7.0": "2024-05-19T20:25:03.615Z",
    "1.7.1": "2024-05-20T13:32:52.757Z",
    "1.7.2": "2024-05-21T16:58:04.163Z"
  }
}
```

**Champ clé :** `time["<version>"]` — la valeur est la date de publication originale sur npmjs.org. Par exemple`2024-05-21T16:58:04.163Z`, `time["1.7.2"]` renvoie l'horodatage exact enregistré par npmjs.org lorsque cette version a été publiée. Pour déterminer l'âge, comparez cette valeur à l'heure actuelle moins votre période de quarantaine.

## Maven
<a name="package-version-age-gating-maven"></a>

Pour les artefacts Maven, CodeArtifact renvoie l'horodatage de publication original de Maven Central dans l'en-tête de réponse `Last-Modified` HTTP lorsque vous téléchargez un fichier (JAR, POM ou autre artefact).

**Requête :**

```
curl -I -H "Authorization: Bearer $CODEARTIFACT_AUTH_TOKEN" \
  https://my-domain-111122223333.d.codeartifact.us-east-1.amazonaws.com/maven/my-repo/\
org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.pom
```

**En-têtes de réponse :**

```
HTTP/2 200
content-type: application/xml
Last-Modified: Fri, 26 Feb 2021 20:40:52 GMT
content-length: 22672
```

**Champ clé :** `Last-Modified` en-tête — il s'agit de la date de publication originale de Maven Central. Comparez-le à votre limite de quarantaine pour déterminer si l'artefact est trop récent.

**Note**  
Le `<lastUpdated>` champ à l'intérieur `maven-metadata.xml` indique la date à laquelle le cache a été actualisé pour la CodeArtifact dernière fois, et non la date de publication en amont. N'utilisez pas d'`maven-metadata.xml`horodatage pour la datation.

## NuGet
<a name="package-version-age-gating-nuget"></a>

Pour les NuGet packages, CodeArtifact renvoie l'horodatage de publication original de nuget.org dans le `published` champ de réponse d'enregistrement de la V3.

**Requête :**

```
curl -H "Authorization: Bearer $CODEARTIFACT_AUTH_TOKEN" \
  https://my-domain-111122223333.d.codeartifact.us-east-1.amazonaws.com/nuget/my-repo/\
v3/registration4/newtonsoft.json/index.json
```

**Réponse (abrégée, montrant une version) :**

```
{
  "items": [{
    "items": [{
      "catalogEntry": {
        "id": "Newtonsoft.Json",
        "version": "13.0.3",
        "published": "2023-03-08T07:42:54.647+00:00",
        "listed": true
      }
    }]
  }]
}
```

**Champ clé :** `catalogEntry.published` — il s'agit de la date de publication originale de nuget.org. Par exemple, `"2023-03-08T07:42:54.647+00:00"` cela signifie que la Newtonsoft.Json version 13.0.3 a été publiée le 8 mars 2023.

## Cargo (rouille)
<a name="package-version-age-gating-cargo"></a>

Pour les caisses Cargo extraites de crates.io, CodeArtifact préserve l'horodatage de publication d'origine dans la réponse de l'API crates.io V1. `versions` Demandez au point de terminaison de l'API V1 une caisse pour lire l'`created_at`horodatage de chaque version.

**Requête :**

```
curl -H "Authorization: Bearer $CODEARTIFACT_AUTH_TOKEN" \
  https://my-domain-111122223333.d.codeartifact.us-east-1.amazonaws.com/cargo/my-repo/\
api/v1/crates/serde/versions
```

**Champ clé :** L'`created_at`horodatage par version indiqué dans la `versions` réponse V1 correspond à la date de publication originale de crates.io.

**Note**  
Cargo utilise le protocole sparse index (`<prefix>/<crate>`) pour la résolution normale des dépendances. L'index clairsemé renvoie`vers`, `cksum``yanked`, et `features` pour chaque version, mais il n'inclut pas d'horodatage de publication. Pour limiter les dépendances de Cargo en fonction de l'âge, interrogez l'API V1 illustrée ci-dessus dans une étape distincte de votre pipeline. La norme `cargo build` et `cargo update` les commandes n'appellent pas l'API V1.

## PyPI
<a name="package-version-age-gating-pypi"></a>

Pour les packages Python, CodeArtifact prend en charge les protocoles PEP 691 (API simple JSON) et PEP 700, qui incluent le `upload-time` champ pour chaque fichier de distribution.

**Requête :**

```
curl -H "Authorization: Bearer $CODEARTIFACT_AUTH_TOKEN" \
  -H "Accept: application/vnd.pypi.simple.v1+json" \
  https://my-domain-111122223333.d.codeartifact.us-east-1.amazonaws.com/pypi/my-repo/simple/requests/
```

**Réponse (abrégée) :**

```
{
  "files": [{
    "filename": "requests-2.31.0-py3-none-any.whl",
    "upload-time": "2023-05-22T15:12:42.313790Z",
    "size": 62574,
    "url": "../../packages/requests/2.31.0/requests-2.31.0-py3-none-any.whl"
  }]
}
```

**Champ clé :** `upload-time` — il s'agit de la date de publication originale de PyPI. Des outils tels que le `uv` prennent en charge de manière native :

```
# Only install versions published before a specific date
uv pip install --exclude-newer 2026-05-01T00:00:00Z -r requirements.txt
```

**Note**  
L'API JSON PEP 691 nécessite l'`Accept: application/vnd.pypi.simple.v1+json`en-tête. L'API HTML Simple par défaut n'inclut pas les horodatages.  
Pour les fichiers de distribution ingérés avant l'introduction de la capture au moment du téléchargement par artefact (anciens enregistrements), le `upload-time` champ peut être absent des entrées. `files[]` Votre logique de blocage doit traiter une version manquante `upload-time` comme une version qu'elle ne peut pas vérifier et décider de l'autoriser ou de la bloquer conformément à votre politique.

## Exemple : synchronisation des packages npm dans CI/CD
<a name="package-version-age-gating-example"></a>

Le script Python suivant lit un `package-lock.json` fichier, CodeArtifact demande l'horodatage de publication de chaque dépendance et sort avec un statut différent de zéro si une version a été publiée dans la fenêtre de quarantaine.

```
#!/usr/bin/env python3
"""
gate_package_age.py - Block npm packages published too recently.

Reads package-lock.json, queries CodeArtifact for each dependency's
publish timestamp, and rejects versions newer than QUARANTINE_HOURS.

Environment variables:
  CODEARTIFACT_AUTH_TOKEN  - from `aws codeartifact get-authorization-token`
  CODEARTIFACT_NPM_ENDPOINT - from `aws codeartifact get-repository-endpoint`
  QUARANTINE_HOURS - minimum version age in hours (default: 72)
"""
import json, os, sys, urllib.request
from datetime import datetime, timezone, timedelta

def get_publish_time(endpoint, token, package, version):
    """Fetch the publish timestamp for a specific version from CodeArtifact."""
    url = f"{endpoint.rstrip('/')}/{package}"
    req = urllib.request.Request(url, headers={"Authorization": f"Bearer {token}"})
    data = json.loads(urllib.request.urlopen(req, timeout=30).read())
    time_str = data.get("time", {}).get(version)
    if not time_str:
        return None
    return datetime.fromisoformat(time_str.replace("Z", "+00:00"))

token = os.environ["CODEARTIFACT_AUTH_TOKEN"]
endpoint = os.environ["CODEARTIFACT_NPM_ENDPOINT"]
quarantine_hours = int(os.environ.get("QUARANTINE_HOURS", "72"))
cutoff = datetime.now(timezone.utc) - timedelta(hours=quarantine_hours)

with open("package-lock.json") as f:
    lockfile = json.load(f)

blocked = []
checked = 0
for path, info in lockfile.get("packages", {}).items():
    if not path.startswith("node_modules/"):
        continue
    name = path.replace("node_modules/", "", 1)
    version = info.get("version")
    if not name or not version:
        continue
    checked += 1
    pub_time = get_publish_time(endpoint, token, name, version)
    if pub_time and pub_time > cutoff:
        age_h = (datetime.now(timezone.utc) - pub_time).total_seconds() / 3600
        blocked.append(f"  {name}@{version} (age: {age_h:.0f}h, published {pub_time.isoformat()})")

if blocked:
    print(f"BLOCKED: {len(blocked)} package(s) newer than {quarantine_hours} hours:")
    print("\n".join(blocked))
    sys.exit(1)
print(f"PASSED: all {checked} packages older than {quarantine_hours} hours.")
```

**CI/CD intégration :**

```
# Step 1: Authenticate
export CODEARTIFACT_AUTH_TOKEN=$(aws codeartifact get-authorization-token \
  --domain my-domain --domain-owner 111122223333 \
  --query authorizationToken --output text)

export CODEARTIFACT_NPM_ENDPOINT=$(aws codeartifact get-repository-endpoint \
  --domain my-domain --domain-owner 111122223333 \
  --repository my-repo --format npm \
  --query repositoryEndpoint --output text)

# Step 2: Set quarantine window (72 hours = 3 days)
export QUARANTINE_HOURS=72

# Step 3: Generate lockfile without installing
npm install --package-lock-only

# Step 4: Gate on age — fails if any dependency is too new
python3 gate_package_age.py

# Step 5: If gate passes, install
npm ci
```

**Exemple de sortie lorsqu'un package est bloqué :**

```
BLOCKED: 1 package(s) newer than 72 hours:
  evil-package@1.0.0 (age: 2h, published 2026-06-03T08:30:00+00:00)
```

**Exemple de sortie lorsque tous les packages sont transmis :**

```
PASSED: all 847 packages older than 72 hours.
```

## Attaques atténuées
<a name="package-version-age-gating-attacks"></a>


| Le type d'attaque | Comment ça marche | Comment la datation peut vous aider | 
| --- | --- | --- | 
| Confusion de dépendance | L'attaquant publie un package de haute version portant le même nom qu'un package interne dans un registre public. | La version malveillante est toute nouvelle. Bloqué par une fenêtre de quarantaine. | 
| Prise de contrôle de compte | Un attaquant compromet les informations d'identification d'un responsable et publie une mise à jour malveillante (par exemple, event-stream). | La nouvelle version est conservée. La communauté le détecte et le rétablit pendant la période de quarantaine. | 
| Typosquattage | L'attaquant publie un package avec un nom similaire à un package populaire (par exemple, lodashs au lieu delodash). | Toutes les versions du package typosquat sont nouvelles. Toutes les versions sont bloquées. | 
| Star-jacking | Un attaquant injecte un logiciel malveillant dans une version de correctif d'un package légitime qu'il contrôle. | Le correctif malveillant est une version récemment publiée. Bloqué jusqu'à ce qu'il vieillit après la période de quarantaine. | 

## Résumé des formats pris en charge
<a name="package-version-age-gating-summary"></a>


| Format | Où lire l'horodatage de publication | Champ clé | Statut | 
| --- | --- | --- | --- | 
| npm | Réponse au colis () GET /<package> | time["<version>"] | Available | 
| Maven | En-tête de réponse HTTP lors du téléchargement de l'artefact | Last-Modified | Available | 
| NuGet | Indice d'enregistrement V3 | catalogEntry.published | Available | 
| Cargo | Réponse aux versions de l'API V1 | created\_at | Available | 
| PyPI | API simple PEP 691 JSON | upload-time | Available | 