Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions codecarbon/cli/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,15 @@ def _discover_endpoints():

def _save_credentials(tokens):
"""Save OAuth tokens to the local credentials file."""
with open(_CREDENTIALS_FILE, "w") as f:
json.dump(tokens, f)
try:
with open(_CREDENTIALS_FILE, "w") as f:
json.dump(tokens, f)
except OSError as e:
raise ValueError(
f"Could not write the credentials file {_CREDENTIALS_FILE.resolve()} "
f"(error: {e}). Please run the command from a directory you can "
"write to."
)


def _load_credentials():
Expand Down Expand Up @@ -169,6 +176,7 @@ def authorize():
server = HTTPServer(("localhost", _REDIRECT_PORT), _CallbackHandler)

print("Opening browser for authentication...")
print(f"If no browser opens, copy this URL into your browser:\n{uri}")
webbrowser.open(uri)

server.handle_request()
Expand Down
28 changes: 23 additions & 5 deletions docs/how-to/linux-service.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,33 @@ Install CodeCarbon in the virtual environment:
sudo -u codecarbon /opt/codecarbon/.venv/bin/pip install codecarbon
```

### Step 3: Authenticate with CodeCarbon
### Step 3: Get Your Dashboard Credentials

Go to <https://dashboard.codecarbon.io/> and create an account to get your API key. Then authenticate locally:
Go to <https://dashboard.codecarbon.io/> and create an account.

Configure CodeCarbon:
Run the login and configuration wizard **as your own user**, not as the `codecarbon`
service user: `codecarbon login` needs a web browser and writes a `credentials.json`
file in the current directory, two things the service user does not have. The service
itself never uses those credentials, only the `api_key` you will write in its
configuration file at Step 6.

From your own account, in a directory you can write to:

``` bash
sudo -u codecarbon /opt/codecarbon/.venv/bin/codecarbon login
pip install codecarbon # or run it with `uvx codecarbon`
codecarbon login
codecarbon config
```

`codecarbon config` asks you to pick or create an organization, a project and an
experiment, then writes their ids and an API key to `~/.codecarbon.config`. Keep that
file at hand, you will copy its values into the service configuration at Step 6.

If the machine has no browser (headless server), `codecarbon login` prints the
authentication URL: open it in a browser on the same machine, or forward the callback
port over SSH with `ssh -L 8090:localhost:8090 user@server` and open the URL on your
laptop, so that the `http://localhost:8090/callback` redirect reaches the CLI.

### Step 4: Create a Systemd Service File

Create the service configuration file for systemd:
Expand Down Expand Up @@ -107,7 +124,8 @@ group means no other local account gains anything from this change.

### Step 6: Create the CodeCarbon Configuration File

Configure CodeCarbon with your dashboard credentials:
Copy the ids and the API key from the `~/.codecarbon.config` written at Step 3 into the
service configuration file:

``` bash
sudo tee /opt/codecarbon/.codecarbon.config <<EOF
Expand Down
8 changes: 8 additions & 0 deletions tests/cli/test_cli_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,14 @@ def test_save_and_load_credentials(self, mock_open):
loaded = auth._load_credentials()
self.assertEqual(loaded, tokens)

@patch("builtins.open", side_effect=PermissionError(13, "Permission denied"))
def test_save_credentials_unwritable_directory(self, mock_open):
with self.assertRaises(ValueError) as ctx:
auth._save_credentials({"access_token": "a"})
message = str(ctx.exception)
self.assertIn(str(auth._CREDENTIALS_FILE.resolve()), message)
self.assertIn("Permission denied", message)

@patch("codecarbon.cli.auth.requests.get")
@patch("codecarbon.cli.auth.KeySet.import_key_set")
@patch("codecarbon.cli.auth.jose_jwt.decode")
Expand Down
Loading