Aller au contenu principal

Shell : exécution de commandes

Shell : execution de commandes

L’outil Shell permet au modele d’executer des commandes systeme dans un environnement controle. C’est la passerelle entre l’IA et votre infrastructure : deploiements, scripts de maintenance, diagnostics systeme, tout devient automatisable.

Concept et architecture

Contrairement a Code Interpreter qui execute du Python dans un sandbox isole, l’outil Shell execute des commandes dans un environnement configurable. L’execution peut se faire localement ou dans un container dedie :

from openai import OpenAI

client = OpenAI()

# L'outil Shell est utilise via le Agents SDK
# car il necessite un environnement d'execution controle
from agents import Agent, Runner

agent = Agent(
    name="devops-assistant",
    model="gpt-5.3",
    instructions=(
        "Tu es un assistant DevOps. Tu executes des commandes systeme "
        "pour diagnostiquer et resoudre des problemes d'infrastructure. "
        "Explique chaque commande avant de l'executer."
    ),
    tools=[{"type": "shell"}]
)

Cas d’usage : diagnostic systeme

# L'agent peut executer des commandes de diagnostic
agent = Agent(
    name="diagnostic",
    model="gpt-5.3",
    instructions=(
        "Diagnostique l'etat du systeme en executant les commandes appropriees. "
        "Commence par les verifications basiques (disque, memoire, CPU) "
        "puis approfondis selon les symptomes."
    ),
    tools=[{"type": "shell"}]
)

# L'agent executera des commandes comme :
# df -h          -> espace disque
# free -m        -> memoire
# top -bn1       -> charge CPU
# systemctl status nginx  -> etat des services

Securiser l’execution

L’outil Shell est puissant mais dangereux. Implementez des garde-fous :

# Pattern : fonction wrapper avec validation
import subprocess
import shlex

COMMANDES_AUTORISEES = {
    "diagnostique": ["df", "free", "top", "uptime", "ps", "netstat", "curl", "ping"],
    "deploiement": ["git", "docker", "npm", "pip"],
    "fichiers": ["ls", "cat", "head", "tail", "wc", "grep", "find"],
}

COMMANDES_INTERDITES = ["rm", "dd", "mkfs", "shutdown", "reboot", "kill", "passwd"]

def executer_commande_securisee(commande: str, categorie: str = "diagnostique") -> dict:
    """Execute une commande avec validation de securite."""
    # Parser la commande
    parties = shlex.split(commande)
    executable = parties[0]

    # Verifier les interdictions
    if executable in COMMANDES_INTERDITES:
        return {
            "erreur": f"Commande interdite : {executable}",
            "raison": "Cette commande est dans la liste des commandes bloquees"
        }

    # Verifier les autorisations
    autorisees = COMMANDES_AUTORISEES.get(categorie, [])
    if executable not in autorisees:
        return {
            "erreur": f"Commande non autorisee dans la categorie '{categorie}'",
            "autorisees": autorisees
        }

    # Executer avec timeout
    try:
        result = subprocess.run(
            parties,
            capture_output=True,
            text=True,
            timeout=30,
            cwd="/tmp"  # Repertoire de travail restreint
        )
        return {
            "stdout": result.stdout,
            "stderr": result.stderr,
            "code_retour": result.returncode
        }
    except subprocess.TimeoutExpired:
        return {"erreur": "Timeout : la commande a depasse 30 secondes"}

Implementer comme fonction personnalisee

En attendant l’outil Shell natif dans la Responses API, vous pouvez implementer l’execution de commandes via le function calling :

tools = [
    {
        "type": "function",
        "name": "executer_commande",
        "description": (
            "Executer une commande shell sur le serveur. "
            "Commandes autorisees : diagnostic systeme (df, free, top, uptime, ps), "
            "lecture de fichiers (ls, cat, head, tail, grep), "
            "reseau (curl, ping, netstat). "
            "Les commandes destructives sont interdites."
        ),
        "parameters": {
            "type": "object",
            "properties": {
                "commande": {
                    "type": "string",
                    "description": "La commande shell a executer"
                },
                "repertoire": {
                    "type": "string",
                    "description": "Repertoire de travail (defaut: /tmp)"
                }
            },
            "required": ["commande"],
            "additionalProperties": false
        },
        "strict": true
    }
]

import json

def traiter_appels(response):
    resultats = []
    for item in response.output:
        if item.type == "function_call" and item.name == "executer_commande":
            args = json.loads(item.arguments)
            resultat = executer_commande_securisee(
                args["commande"],
                categorie="diagnostique"
            )
            resultats.append({
                "type": "function_call_output",
                "call_id": item.call_id,
                "output": json.dumps(resultat)
            })
    return resultats

# Boucle complete
response = client.responses.create(
    model="gpt-5.3",
    input="Verifie l'espace disque et la memoire disponible",
    tools=tools
)

resultats = traiter_appels(response)
response_finale = client.responses.create(
    model="gpt-5.3",
    input=response.output + resultats,
    tools=tools
)
print(response_finale.output_text)

Workflows d’automatisation

Deploiement automatise

tools_deploy = [
    {
        "type": "function",
        "name": "executer_etape_deploy",
        "description": (
            "Executer une etape de deploiement. "
            "Etapes possibles : git_pull, tests, build, deploy, rollback. "
            "Chaque etape est validee avant de passer a la suivante."
        ),
        "parameters": {
            "type": "object",
            "properties": {
                "etape": {
                    "type": "string",
                    "enum": ["git_pull", "tests", "build", "deploy", "rollback"]
                },
                "parametres": {
                    "type": "object",
                    "properties": {
                        "branche": {"type": "string"},
                        "environnement": {"type": "string", "enum": ["staging", "production"]}
                    }
                }
            },
            "required": ["etape"],
            "additionalProperties": false
        },
        "strict": true
    }
]

def executer_etape(etape: str, parametres: dict) -> dict:
    scripts = {
        "git_pull": "cd /app && git pull origin {branche}",
        "tests": "cd /app && npm test",
        "build": "cd /app && npm run build",
        "deploy": "cd /app && ./deploy.sh {environnement}",
        "rollback": "cd /app && ./rollback.sh {environnement}"
    }
    commande = scripts[etape].format(**parametres)
    return executer_commande_securisee(commande, "deploiement")

Monitoring et alertes

def verifier_sante_systeme() -> dict:
    """Verifie la sante du systeme et retourne un rapport."""
    checks = {}

    # Espace disque
    r = executer_commande_securisee("df -h /", "diagnostique")
    checks["disque"] = r

    # Memoire
    r = executer_commande_securisee("free -m", "diagnostique")
    checks["memoire"] = r

    # Services
    for service in ["nginx", "postgresql", "redis"]:
        r = executer_commande_securisee(
            f"systemctl is-active {service}",
            "diagnostique"
        )
        checks[f"service_{service}"] = r

    return checks

# L'IA analyse les resultats et propose des actions
response = client.responses.create(
    model="gpt-5.3",
    input=f"Analyse ce rapport de sante systeme et identifie les problemes :\n"
          f"{json.dumps(verifier_sante_systeme(), indent=2)}",
    tools=tools
)

Points cles a retenir

  • L’outil Shell connecte le modele a votre infrastructure
  • Implementez des listes blanches et noires de commandes
  • Utilisez des timeouts et des repertoires de travail restreints
  • Le function calling permet d’implementer Shell comme outil personnalise
  • Combinez Shell avec d’autres outils pour des workflows DevOps complets