CLI Configuration ================= The Heartlock CLI is a single-binary Go client that authenticates via the browser, fetches project secrets from the API, and injects them as environment variables into a child process — mirroring ``infisical run``. Installing ---------- Pre-built binaries for Linux and macOS (amd64 and arm64) are attached to every release: https://yena.dev/Jouleworks/heartlock/releases/latest/ Install or upgrade with the download script: .. code-block:: bash curl -fsSL https://yena.dev/Jouleworks/heartlock/raw/branch/main/scripts/download.sh | bash This detects your OS and architecture, downloads the latest binary, and places it on your ``PATH``. To inspect the script first: https://yena.dev/Jouleworks/heartlock/raw/branch/main/scripts/download.sh Building from source -------------------- .. code-block:: bash cd cli go mod tidy make build # produces ./bin/heartlock Other Make targets: .. list-table:: :widths: 20 80 :header-rows: 1 * - Target - Description * - ``build`` - Build ``./bin/heartlock`` for the host platform * - ``run`` - Build then run with ``ARGS="..."``, e.g. ``make run ARGS="whoami"`` * - ``test`` - ``go test ./...`` * - ``vet`` - ``go vet ./...`` * - ``tidy`` - ``go mod tidy`` * - ``release`` - Cross-compile linux+darwin / amd64+arm64 into ``dist/`` * - ``clean`` - Remove ``bin/`` and ``dist/`` Commands -------- ``heartlock login [--server URL] [--force|-f]`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Browser-based authentication. Starts a local callback server on an ephemeral port, opens the browser to ``/cli/login?callback=http://localhost:/callback``, captures the service token delivered by the redirect, validates it against ``/auth/me/``, and persists it. If a stored token already exists for the resolved server, ``login`` first verifies it. When it is still valid, ``login`` prints the account and exits without opening a browser. When the server rejects it (revoked/expired), ``login`` automatically re-runs the browser flow. Use ``--force`` (or ``-f``) to skip the check and re-authenticate regardless. .. note:: Any command that receives a ``401`` response clears the stored token for that server automatically, so the next ``heartlock login`` performs a fresh sign-in. ``heartlock whoami`` ^^^^^^^^^^^^^^^^^^^^ Prints the currently authenticated user (calls ``/auth/me/``). ``heartlock projects`` ^^^^^^^^^^^^^^^^^^^^^^ Lists projects accessible to the authenticated user (NAME / SLUG / ROLE). ``heartlock environments --project `` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Lists environments for a project. ``--project`` accepts a **slug** (looked up against the projects list), a name, or a UUID. ``heartlock secrets --project --env `` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Lists secrets as a table (KEY / VALUE / COMMENT). ``--reveal`` Show plaintext values (values are masked with ``••••••••`` by default). ``--env-only`` Print ``KEY=value``, one per line, suitable for shell sourcing. ``heartlock run --project --env [-- command args...]`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Fetches secrets via the **export** endpoint and execs the child command with them injected into the environment. ``--preserve-env`` Existing environment variables **win**; fetched secrets only fill in variables that are not already set. Without this flag, fetched secrets **override** existing variables. The ``--`` separator distinguishes Heartlock flags from the command and its arguments. Exit status is the child's exit status. Signals (``SIGINT``, ``SIGTERM``) are forwarded to the child. ``heartlock import-env [--project ] [--env ] [file]`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Reads a ``.env`` file and stores each ``KEY=value`` as a secret in the target environment. ``--project`` / ``--env`` fall back to ``default_project`` / ``default_env`` from the config file. ``-f/--file`` Select the source file; defaults to ``.env``. Use ``-`` to read from stdin. ``--overwrite`` Update the value of variables that already exist instead of skipping them. ``--dry-run`` Parse and print the plan without writing anything. Existing variables are skipped unless ``--overwrite`` is given; a ``403`` response means your role lacks write access. ``heartlock logout`` ^^^^^^^^^^^^^^^^^^^^ Removes the stored token for the active profile. ``heartlock config [--server URL]`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Shows the current server, active profile, login state, and config path. With ``--server URL``, sets the default server for the active profile. Configuration file ------------------ The configuration lives under the OS user-config directory in a ``heartlock`` subdirectory: .. list-table:: :widths: 15 85 :header-rows: 1 * - OS - Path * - Linux - ``~/.config/heartlock/config.json`` * - macOS - ``~/Library/Application Support/heartlock/config.json`` * - Windows - ``%AppData%\heartlock\config.json`` The file is created with permissions ``0600``. Example structure: .. code-block:: json { "server": "http://localhost:8082", "default_project": "web", "default_env": "dev", "active_profile": "default", "profiles": { "default": { "server": "http://localhost:8082", "token": "", "user": { "id": "...", "email": "you@example.com" } } } } .. warning:: The token is stored in plaintext in ``config.json`` for the current version. Integration with the OS keychain / credential store is a planned improvement. Configuration precedence ------------------------ Overrides are resolved from highest to lowest priority: 1. **Flags**: ``--server``, ``--token`` 2. **Environment**: ``HEARTLOCK_SERVER``, ``HEARTLOCK_TOKEN`` 3. **Active profile**: ``server`` / ``token`` in the named profile 4. **Top-level config**: ``server`` key 5. **Built-in default**: ``http://localhost:8082`` API endpoints used by the CLI ------------------------------ All under ``/api/v1/``, authenticated with a Bearer token via ``Authorization: Bearer ``: .. list-table:: :widths: 60 40 :header-rows: 1 * - Method & Path - Used by * - ``GET /health/`` - ``login`` (reachability check) * - ``GET /auth/me/`` - ``login``, ``whoami`` * - ``GET /projects/`` - ``projects``, slug resolution * - ``GET /projects/{project_id}/environments/`` - ``environments``, env resolution * - ``GET /projects/{project_id}/environments/{env_id}/secrets/`` - ``secrets`` * - ``GET /projects/{project_id}/environments/{env_id}/secrets/export/`` - ``run`` * - ``POST /projects/{project_id}/environments/{env_id}/secrets/`` - ``import-env`` (create) * - ``PATCH /projects/{project_id}/environments/{env_id}/secrets/{secret_id}/`` - ``import-env`` (update)