Good -- there is no existing usage of `GODOTIQ_DEV_KEY` in the source code yet. Now I have all the context I need to write the section.

# Section 14: LICENSE -- Dev Key Hashing (Issue 14)

## Background

The current `license.py` module contains a plaintext dev bypass on line 119 of `_check_license()`:

```python
if os.environ.get("GODOTIQ_LICENSE", "").lower() == "pro":
    return True
```

This means anyone who sets `GODOTIQ_LICENSE=pro` in their environment gets full PRO access with no validation. This section replaces that bypass with a SHA-256 hashed dev key mechanism. A random passphrase is generated once (offline), its SHA-256 hash is hardcoded as `_DEV_KEY_HASH`, and at runtime the `GODOTIQ_DEV_KEY` environment variable is hashed and compared. The actual passphrase never appears in source code.

## File to Modify

- `/Users/salvatorefarruggio/Desktop/godotiq/src/godotiq/license.py`
- `/Users/salvatorefarruggio/Desktop/godotiq/tests/test_license.py`

## Dependencies

None. This section is fully independent -- it modifies only `license.py` and its tests.

## Tests FIRST

All new tests go in `/Users/salvatorefarruggio/Desktop/godotiq/tests/test_license.py`. They should be added as a new test class alongside the existing tests. The existing `_clean_license_state` autouse fixture already resets the in-process license cache and clears `GODOTIQ_LICENSE` and `GODOTIQ_LICENSE_KEY` env vars before each test, so the new tests benefit from that automatically. The new `GODOTIQ_DEV_KEY` env var should also be cleared in that fixture.

### New test class: `TestDevKeyHash`

```python
class TestDevKeyHash:
    """Tests for SHA-256 hashed dev key replacing plaintext GODOTIQ_LICENSE=pro bypass."""

    # Test: _DEV_KEY_HASH constant is a valid 64-char hex string (SHA-256 digest length)

    # Test: correct GODOTIQ_DEV_KEY env var -> is_pro() returns True
    #   Set GODOTIQ_DEV_KEY to the actual dev passphrase, verify is_pro() is True

    # Test: wrong GODOTIQ_DEV_KEY env var -> is_pro() returns False
    #   Set GODOTIQ_DEV_KEY to "wrong-passphrase", verify is_pro() is False

    # Test: GODOTIQ_LICENSE=pro (old bypass) -> is_pro() returns False
    #   Set GODOTIQ_LICENSE to "pro" with no other env vars, verify is_pro() is False
    #   (This is the critical regression test: the old bypass must no longer work)

    # Test: no env vars at all -> is_pro() returns False
    #   No GODOTIQ_DEV_KEY, no GODOTIQ_LICENSE, no GODOTIQ_LICENSE_KEY -> False

    # Test: empty GODOTIQ_DEV_KEY -> is_pro() returns False
    #   Set GODOTIQ_DEV_KEY to "", verify is_pro() is False

    # Test: GODOTIQ_DEV_KEY takes priority over GODOTIQ_LICENSE_KEY path
    #   If both are set and the dev key is correct, is_pro() returns True
    #   without needing to call Polar API (use mock_polar_unreachable fixture)
```

### Updates to existing tests

The existing `TestIsProDevOverride` class has tests that rely on `GODOTIQ_LICENSE=pro` returning `True`. These tests must be **updated or removed** because the old bypass is being eliminated:

- `test_dev_override_pro` -- must be changed: `GODOTIQ_LICENSE=pro` should now return `False` (or the test should be removed entirely)
- `test_dev_override_case_insensitive` -- same: `GODOTIQ_LICENSE=PRO` should now return `False`
- `test_dev_override_ignores_invalid` -- can stay as-is (community value already returns False)
- `test_community_when_no_env` -- can stay as-is

The `test_dev_override_skips_polar` test in `TestIsProPolarValidation` also relies on `GODOTIQ_LICENSE=pro`. It should be rewritten to use the correct `GODOTIQ_DEV_KEY` instead.

The `_clean_license_state` autouse fixture must be extended to also clear `GODOTIQ_DEV_KEY`:
```python
monkeypatch.delenv("GODOTIQ_DEV_KEY", raising=False)
```

In `TestGatePro`, the tests that use `monkeypatch.setenv("GODOTIQ_LICENSE", "pro")` to simulate a PRO user must be updated to use `GODOTIQ_DEV_KEY` with the actual dev passphrase instead.

### How to obtain the dev passphrase for tests

The implementer needs to know the actual dev passphrase to write tests that verify the correct key works. There are two approaches:

**Approach A (recommended):** Generate the passphrase during implementation, hardcode the hash in `license.py`, and store the passphrase as a constant only in the test file (e.g., `_TEST_DEV_KEY = "the-generated-passphrase"`). This is acceptable because tests are not shipped to end users, and the passphrase is only useful to developers who already have source access.

**Approach B:** Export a module-level test helper from `license.py` that tests can use. Not recommended since it would expose the key checking more broadly.

## Implementation Details

### Step 1: Generate a dev key and its hash

Use Python's `secrets` module to generate a secure random passphrase of 32+ characters. Compute its SHA-256 hash. The hash will be hardcoded in the source; the passphrase will be known only to the developer (and stored in the test file for CI).

Example generation (run once, offline):
```python
import secrets, hashlib
key = secrets.token_urlsafe(32)  # ~43 chars of URL-safe random
h = hashlib.sha256(key.encode("utf-8")).hexdigest()
print(f"Dev key: {key}")
print(f"Hash:    {h}")
```

### Step 2: Add `_DEV_KEY_HASH` constant to `license.py`

Near the top of the file, after the existing constants section, add:

```python
_DEV_KEY_HASH = "<64-char-hex-string>"  # SHA-256 of the dev key
```

This is a module-level constant. It must be a valid 64-character lowercase hex string.

### Step 3: Replace the `GODOTIQ_LICENSE=pro` bypass in `_check_license()`

The current `_check_license()` function at line 116-146 has this as its first check:

```python
# 1. Dev/test override
if os.environ.get("GODOTIQ_LICENSE", "").lower() == "pro":
    return True
```

Replace this block with:

```python
# 1. Dev key override (SHA-256 hashed)
dev_key = os.environ.get("GODOTIQ_DEV_KEY", "").strip()
if dev_key:
    if hashlib.sha256(dev_key.encode("utf-8")).hexdigest() == _DEV_KEY_HASH:
        return True
    # Wrong dev key -- fall through to license key check, do not return False
    # (user might have both GODOTIQ_DEV_KEY and GODOTIQ_LICENSE_KEY set)
```

Key behavioral notes:
- An incorrect `GODOTIQ_DEV_KEY` does **not** short-circuit to `False`. It falls through to the `GODOTIQ_LICENSE_KEY` Polar.sh validation path. This prevents accidentally locking out a user who has a valid Polar key but a stale dev key in their env.
- An empty or missing `GODOTIQ_DEV_KEY` also falls through (no change to current behavior for that path).

### Step 4: Update the module docstring

The module docstring at the top of `license.py` currently documents:
```
1. GODOTIQ_LICENSE=pro  -- dev/test override only (bypasses validation)
```

Update this line to:
```
1. GODOTIQ_DEV_KEY      -- SHA-256 hashed dev key (replaces GODOTIQ_LICENSE=pro)
```

Also update the `is_pro()` function's docstring similarly.

### Step 5: Remove all references to the old `GODOTIQ_LICENSE=pro` bypass

Search for any remaining references to `GODOTIQ_LICENSE=pro` or the concept of a plaintext override in comments within `license.py` and remove or update them. The `GODOTIQ_LICENSE` env var is no longer checked at all in `_check_license()`.

### Security Notes

- The passphrase itself never appears in `license.py` -- only the SHA-256 hash, which is not reversible.
- The passphrase is stored in the test file for CI purposes. This is acceptable because anyone with source access can already read the hash and, more importantly, can simply modify the source code to bypass any license check. The dev key mechanism prevents casual `GODOTIQ_LICENSE=pro` bypass by end users of the distributed package; it does not aim to prevent developers with source access from bypassing the check.
- The `hashlib` module is already imported in `license.py` (used by `_hash_key()`), so no new imports are needed.

### Summary of changes

| File | Change |
|------|--------|
| `src/godotiq/license.py` | Add `_DEV_KEY_HASH` constant; replace `GODOTIQ_LICENSE=pro` check with `GODOTIQ_DEV_KEY` SHA-256 comparison; update docstrings |
| `tests/test_license.py` | Add `TestDevKeyHash` class with 6-7 tests; update `_clean_license_state` fixture to clear `GODOTIQ_DEV_KEY`; update existing tests that relied on `GODOTIQ_LICENSE=pro` |

---

## Implementation Results

### Files Modified
- `src/godotiq/license.py` — Added `_DEV_KEY_HASH`, `import hmac`; replaced plaintext bypass with SHA-256 dev key check using `hmac.compare_digest()`
- `tests/test_license.py` — Added `TestDevKeyHash` (8 tests), updated 6 existing tests from `GODOTIQ_LICENSE=pro` to `GODOTIQ_DEV_KEY`, updated fixture

### Deviations from Plan
1. **`hmac.compare_digest()`** used instead of `==` for hash comparison (code review fix — prevents timing side-channel)
2. **8 tests in TestDevKeyHash** instead of 6-7 (added `test_whitespace_padded_dev_key_works` from code review)
3. **Total test count**: 102 tests (was 94 pre-section)