Aller au contenu
s3nd.sh

@s3nd/cli

Un fichier entre deux machines, avec un code.

Déplacez un fichier avec put et get, vérifiez qu’un bucket est réellement prêt à recevoir des transferts avec doctor, et gardez les réglages dans un fichier que vous pouvez versionner. Directement vers S3 sans rien déployer, ou via votre propre serveur avec un jeton.

Référence de la CLISans serveurnpm
$ s3nd put ./report.pdf
report.pdf · 284 kB · expires in 1 day
K7QP2M4X

$ CODE=$(s3nd put ./report.pdf)          # the code is stdout, the rest is stderr
$ tar cz ./project | s3nd put - --name project.tar.gz

# on the other machine
$ s3nd get K7QP2M4X
Wrote /home/you/report.pdf · 284 kB

$ s3nd get K7QP2M4X -o -  | less        # or to stdout
$ s3nd rm K7QP2M4X
Burned K7QP2M4X

setup et doctor

Quelques questions, puis la preuve que ça marche.

setup demande où stocker les transferts, le bucket et les clés, les enregistre pour cette machine et lance doctor. Une mauvaise configuration S3 échoue tard et vaguement ; doctor effectue les opérations dont s3nd a réellement besoin et rapporte ce qui s’est passé, plutôt que de lire votre policy et de raisonner dessus. L’objet sonde est supprimé avant de rendre la main.

une question à la fois, puis depuis n’importe quel dossier
$ s3nd setup
? Where should transfers be stored?
  AWS S3
❯ Cloudflare R2                  no egress fees
  Scaleway
  …
  ↑↓ to move · Enter to pick
  Dashboard → R2 → Overview, "Account ID" in the side panel.
? Cloudflare account ID 8c4f…
? Bucket name transfers
  R2 → Manage API tokens → Create API token, with Object Read & Write on this bucket.
? Access key ID 5d1e…1a2b
? Secret access key (hidden) ••••••••••••••••

✓ Saved ~/.config/s3nd/config.json (readable by you only)
  Cloudflare R2 · bucket "transfers" · credentials: key …1a2b

Checking it works…
✓ Write, read, delete: round-tripped a probe object
Ready. Send something:
  s3nd put ./a-file
et la vérification qui justifie la commande
$ s3nd doctor
Using ~/.config/s3nd/config.json
✓ Configuration: bucket "transfers", region "auto"
✓ Credentials: resolved, key ends in 1a2b
✓ Bucket reachable: HeadBucket succeeded
✓ Write, read, delete: round-tripped a probe object
! Expiry cleanup: no enabled expiration rule
  → Add an S3 lifecycle rule that expires objects under this bucket after a day or
    two. Without it, expired transfers stay stored and billed.

1 check(s) failed.

Cette dernière vérification est celle que personne ne découvre avant l’arrivée d’une facture. expiresIn empêche un transfert d’être remis ; seule une règle de cycle de vie supprime l’objet. Pointé sur un serveur, doctor vérifie la seule chose qui compte là-bas, un vrai aller-retour, et sort avec un code non nul en cas d’échec, donc il sert de smoke test de déploiement.

Configuration

Des réglages versionnables, des clés qui ne le sont pas.

${VAR} est lu depuis l’environnement, et envFile nomme un fichier à charger d’abord sans écraser ce que le shell a déjà défini. Les profils tiennent plusieurs configurations dans un seul fichier. Un flag bat une variable, qui bat le fichier.

s3nd.config.json
{
  "envFile": ".env",
  "profiles": {
    "r2": {
      "bucket": "transfers",
      "region": "auto",
      "endpoint": "https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com",
      "expiresIn": "24h",
      "credentials": { "accessKeyId": "${R2_ACCESS_KEY_ID}", "secretAccessKey": "${R2_SECRET_ACCESS_KEY}" }
    },
    "local": { "bucket": "transfers", "endpoint": "http://localhost:9000" },
    "prod":  { "remote": "https://drop.example.com/api/transfers", "token": "${S3ND_TOKEN}" }
  }
}
$ s3nd -p local doctor          # against a MinIO container, offline
$ s3nd -p r2 put ./report.pdf
$ s3nd -p prod put ./report.pdf # through your server, with a token

$ s3nd config                   # which value won, and where it came from
file         /home/you/transfers/s3nd.config.json (profile "r2")
mode         straight to S3
bucket       transfers                                 $S3ND_BUCKET
endpoint     https://8c4….r2.cloudflarestorage.com     s3nd.config.json (r2)
credentials  …1a2b                                     s3nd.config.json (r2)
expires in   1 day                                     s3nd.config.json (r2)

Le fichier est cherché depuis le répertoire courant vers le haut, puis dans ~/.config/s3nd/config.json. s3nd config masque l’identifiant de clé et n’affiche jamais le secret ni le jeton. L’environnement seul fonctionne aussi, ce qui est la forme que veut la CI.

Contre votre propre serveur

Une implémentation, deux câblages.

Chaque commande accepte --remote, qui la pointe sur un déploiement du protocole de transfert au lieu de S3. La CLI a exactement une implémentation, le client du protocole, branchée soit sur fetch, soit directement sur le handler dans le même processus. Les deux modes ne peuvent pas diverger.

$ s3nd --remote https://drop.example.com/api/transfers --token "$TOKEN" put ./report.pdf
K7QP2M4X

$ s3nd doctor --remote https://drop.example.com/api/transfers --token "$TOKEN"
✓ Server: https://drop.example.com/api/transfers answered
✓ Create, read, delete: round-tripped code 8WTXQC8R

Conséquence pratique : la machine d’où vous lancez ça a besoin d’un jeton pour votre propre déploiement plutôt que d’identifiants S3. C’est la forme qui convient à une équipe, où donner les clés du bucket à chaque laptop ne convient pas.

s3nd init --provider remote écrit le point de départ correspondant, et doctor --remote prouve que le serveur répond avant que quiconque n’en dépende.

Mettre en place un serveur

Référence

Six commandes, une douzaine d’options.

Commandes

put <file>
Stocke un fichier et affiche le code à transmettre. "-" lit stdin
get <code>
Récupère ce qu’un code désigne, vers le nom de fichier stocké, -o, ou stdout
rm <code>
Brûle un code
doctor
Vérifie que cette configuration peut réellement stocker des transferts. Code de sortie non nul quand une vérification échoue
init
Écrit un s3nd.config.json de départ pour aws, r2, minio, scaleway, wasabi ou remote
config
Affiche la configuration résolue, et d’où vient chaque valeur

Options

-c, --config
Fichier de configuration à lire
-p, --profile
Profil à utiliser dedans
--env-file
Lit d’abord des paires KEY=value depuis ce fichier
--bucket, --prefix, --region, --endpoint
Réglages du bucket, prioritaires sur le fichier et l’environnement
--expires-in
3600, 30m, 24h, 7d, ou never
--remote, --token
Parle à un serveur s3nd plutôt qu’à S3 directement
--name
Nom de fichier sous lequel stocker le transfert
--json
Sortie lisible par une machine, pour les scripts et pour doctor en CI

Sinon, la configuration vient des mêmes variables d’environnement que la bibliothèque : S3ND_BUCKET, S3ND_ENDPOINT, S3ND_REMOTE, S3ND_TOKEN et les identifiants AWS habituels. Node 20 ou plus ; l’analyse des arguments est le parseArgs de node:util, donc il n’y a rien d’autre à installer.

Déposez un fichier. Donnez le code.

Pointez-le sur le bucket que vous payez déjà. Rien à déployer, aucune inscription, personne au milieu.