From 122d8a89d0d1ce200edee27e0c30aa02cdd5c6c1 Mon Sep 17 00:00:00 2001 From: gilesb Date: Wed, 7 Jan 2026 17:23:01 +0000 Subject: [PATCH] feat: add auth to publish command and document authentication MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Publish command now requires login and sends auth token - Added Authentication section to README with login/register docs - Uses L2 server for authentication when publishing runs 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- README.md | 40 ++++++++++++++++++++++++++++++++++++++++ artdag.py | 34 +++++++++++++++++++++++----------- 2 files changed, 63 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index dc002ec..eab50f7 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,46 @@ export ARTDAG_SERVER=http://localhost:8100 ./artdag.py --server http://localhost:8100 ``` +## Authentication + +The client authenticates against an L2 server for commands that require login (e.g., `run`, `publish`). + +```bash +# Set L2 server URL (default: http://localhost:8200) +export ARTDAG_L2=https://artdag.rose-ash.com + +# Or pass with every command +./artdag.py --l2 https://artdag.rose-ash.com +``` + +### Login +```bash +./artdag.py login +# You'll be prompted for your password + +# Or specify password with -p flag (will prompt) +./artdag.py login -p +``` + +### Register +```bash +./artdag.py register +# You'll be prompted to enter and confirm your password + +# Optionally include email +./artdag.py register --email user@example.com +``` + +### Check Current User +```bash +./artdag.py whoami +``` + +### Logout +```bash +./artdag.py logout +``` + ## Commands ### Server Info diff --git a/artdag.py b/artdag.py index dc782ed..b61bdca 100755 --- a/artdag.py +++ b/artdag.py @@ -385,22 +385,34 @@ def assets(): @cli.command() @click.argument("run_id") @click.argument("output_name") -@click.option("--l2", envvar="ARTDAG_L2", default="http://localhost:8200", - help="L2 server URL") -def publish(run_id, output_name, l2): - """Publish an L1 run to L2 (register ownership). +def publish(run_id, output_name): + """Publish an L1 run to L2 (register ownership). Requires login. RUN_ID: The L1 run ID to publish OUTPUT_NAME: Name for the registered asset """ - # Post to L2 server - resp = requests.post( - f"{l2}/registry/record-run", - json={"run_id": run_id, "output_name": output_name} - ) - resp.raise_for_status() - result = resp.json() + # Check auth + token_data = load_token() + if not token_data.get("access_token"): + click.echo("Not logged in. Please run: artdag login ", err=True) + sys.exit(1) + # Post to L2 server with auth + try: + resp = requests.post( + f"{get_l2_server()}/registry/record-run", + json={"run_id": run_id, "output_name": output_name}, + headers={"Authorization": f"Bearer {token_data['access_token']}"} + ) + if resp.status_code == 401: + click.echo("Authentication failed. Please login again.", err=True) + sys.exit(1) + resp.raise_for_status() + except requests.RequestException as e: + click.echo(f"Failed to publish: {e}", err=True) + sys.exit(1) + + result = resp.json() click.echo(f"Published to L2!") click.echo(f"Asset: {result['asset']['name']}") click.echo(f"Hash: {result['asset']['content_hash']}")