Skip to content

1.0.0 - #81

Open
rtuszik wants to merge 16 commits into
mainfrom
organize
Open

rtuszik wants to merge 16 commits into
mainfrom
organize

Conversation

@rtuszik

@rtuszik rtuszik commented May 28, 2026 •

Copy link
Copy Markdown
Owner

TODO:

  • update readme to reflect new package structure
  • allow invocation with uv run koalakeys

@socket-security

socket-security Bot commented May 28, 2026 •

Copy link
Copy Markdown

@socket-security

socket-security Bot commented May 28, 2026 •

Copy link
Copy Markdown

Warning

Review the following alerts detected in dependencies.

According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.

Action Severity Alert  (click "▶" to expand/collapse)
Warn High
Obfuscated code: pypi prek is 90.0% likely obfuscated

Confidence: 0.90

Location: Package overview

From: pyproject.toml → pypi/prek@0.3.6

ℹ Read more on: This package | This alert | What is obfuscated code?

Next steps: Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support@socket.dev.

Suggestion: Packages should not obfuscate their code. Consider not using packages with obfuscated code.

Mark the package as acceptable risk. To ignore this alert only in this pull request, reply with the comment @SocketSecurity ignore pypi/prek@0.3.6. You can also ignore all packages with @SocketSecurity ignore-all. To ignore an alert for all future pull requests, use Socket's Dashboard to change the triage state of this alert.

View full report

@github-actions

github-actions Bot commented May 28, 2026 •

Copy link
Copy Markdown

Coverage

Coverage Report
FileStmtsMissCoverMissing
src/koalakeys
   generate_cheatsheet.py2014279%58–59, 111–113, 128–129, 150–152, 200–202, 211–213, 223–224, 228, 232, 238–239, 252–278
   logger.py35391%21, 42–43
   template_renderer.py16288%20–21
   theming.py1731691%111, 134, 163–166, 168, 174, 177, 181, 211, 225, 230, 255, 278, 288
   validate_yaml.py1893084%133–135, 234–261, 265–272
TOTAL6149385% 

Tests Skipped Failures Errors Time
158 0 💤 0 ❌ 0 🔥 1.953s ⏱️

@rtuszik rtuszik changed the title Organize 1.0.0 Jun 9, 2026
@rtuszik

rtuszik commented Jun 22, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai

@coderabbitai

coderabbitai Bot commented Jun 22, 2026 •

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get PR details
gh pr view 81 --repo rtuszik/KoalaKeys

echo "---FILES CHANGED---"
gh pr diff 81 --repo rtuszik/KoalaKeys --name-only

echo "---PR COMMENTS---"
gh pr view 81 --repo rtuszik/KoalaKeys --comments

Length of output: 31529


🏁 Script executed:

#!/bin/bash
# Check pyproject.toml for scripts/entry points
cat pyproject.toml

echo "---README---"
cat README.md | head -100

Length of output: 5139



@rtuszik, happy to help! I noticed a few things worth addressing before this is ready to merge:

Outstanding TODOs

  1. README not updated – The README still references the old invocation path (uv run src/generate_cheatsheet.py) and the old src/ structure. It needs to be updated to reflect the new src/koalakeys/ package layout.

  2. uv run koalakeys not yet wired up – pyproject.toml is missing a [project.scripts] entry. You'll need something like:

    [project.scripts]
    koalakeys = "koalakeys:main"

    (adjust the entry point to match your actual main() function location in src/koalakeys/__init__.py or generate_cheatsheet.py).

Other things to check

  • Version mismatch: pyproject.toml has version = "0.6.0" but the PR is titled 1.0.0. Was the bump forgotten?
  • prek dependency: Socket Security flagged prek@0.3.6 as 90% likely containing obfuscated code. It's only a dev dependency, but worth verifying it's intentional/safe before merging.

Would you like me to do a full review of all the changes now?

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Jun 22, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds theme-aware cheat-sheet generation with six built-in themes and user-theme inheritance. Adds koalakeys CLI commands for project initialisation, generation, and validation. Packages layout assets, updates templates and CSS, adds integration and browser tests, and hardens CI and tooling.

Changes

KoalaKeys theming and workflow overhaul

Layer / File(s) Summary
Theme resolution and styling contracts
src/koalakeys/theming.py, src/koalakeys/themes/*, docs/schema/cheatsheet.schema.json, src/koalakeys/validate_yaml.py, yaml_cheatsheet_spec.md
Adds theme token validation, built-in and user-theme resolution, CSS sanitisation, styling fields, and theme documentation.
Generation, scaffolding, and CLI integration
src/koalakeys/generate_cheatsheet.py, src/koalakeys/cli.py, src/koalakeys/scaffold/*, src/koalakeys/layouts/*, src/koalakeys/logger.py, src/koalakeys/template_renderer.py
Updates generation paths and styling, adds explicit status codes, and adds init, generate, and validate commands with project scaffolding.
Theme-aware templates and UI assets
src/koalakeys/templates/*
Adds theme token CSS, new cheatsheet and index styling, configurable template blocks, and conditional dark-mode controls.
Integration, browser, and validation coverage
tests/*, pytest.ini
Adds theme, CLI, scaffold, integration, validation, and Playwright browser tests. Browser tests are excluded by default.
CI, packaging, and developer tooling
.github/*, .pre-commit-config.yml, pyproject.toml
Pins GitHub Actions, restricts workflow permissions, adds browser execution in pytest CI, exposes the package command, and configures Ruff.
User-facing workflow documentation
README.md
Documents installation, CLI commands, output directories, built-in themes, and per-sheet theme configuration.

Priority: ➖ Normal

Estimated code review effort: 5 (Critical) | ~110 minutes

Change: Feature

Merge Risk: 🟡 Moderate · up to 96f3c

Several CLI, security, release-metadata, and documentation defects should be corrected before merging the 1.0.0 release.

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is a version number only. It does not identify the project reorganisation, CLI changes, or packaging updates. Use a concise descriptive title, such as "Reorganise package structure and add the koalakeys CLI".
✅ Passed checks (3 passed)
Check name Status Explanation
Description check ✅ Passed The description identifies README updates and support for invoking the project with uv run koalakeys. Both items relate to the changeset, so the description passes this lenient check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
⚔️ Resolve merge conflicts 💡
  • Resolve merge conflict in branch organize

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
pyproject.toml (2)

3-3: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Align package version with the 1.0.0 release intent.

Line 3 still declares 0.6.0, which conflicts with the stated release target and can break release automation and artefact labelling.

Proposed change
-version = "0.6.0"
+version = "1.0.0"

1-8: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add a CLI script entry for uv run koalakeys.

[project.scripts] is missing, so the uv run koalakeys objective will not work.

Proposed change
 [project]
 name = "koalakeys"
 version = "0.6.0"
 description = "Build interactive, portable cheatsheets from YAML."
 readme = "README.md"
 requires-python = ">=3.9"
 dependencies = ["jinja2>=3.1.6", "python-dotenv>=1.1.1", "ruamel-yaml>=0.18.14"]
+
+[project.scripts]
+koalakeys = "koalakeys.<module_with_main>:main"
🧹 Nitpick comments (2)
.github/workflows/pytest.yml (1)

18-20: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Remove the duplicated non-browser test run.

Line 18-Line 20 already runs pytest, then Line 32-Line 38 runs it again with coverage. Keeping only the coverage run avoids duplicate CI time.

Proposed change
-            - run: |
-                uv run pytest
-
             # Browser/Playwright tests are excluded by default (pytest.ini) and run
             # only on pull requests, where we install Chromium for them.
             - name: Install Playwright browser
               if: github.event_name == 'pull_request'
               run: |
                 uv run playwright install --with-deps chromium

Also applies to: 32-38

tests/conftest.py (1)

9-16: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Consolidate isolated_output into one fixture definition.

Line 9 introduces a shared fixture, but there is also an isolated_output fixture in tests/test_generate_cheatsheet.py (Lines 10-16 in graph context). Keeping both increases drift risk and can create subtle shadowing differences; prefer using only the conftest.py fixture.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f15c7b39-fc7a-4cef-ac6b-5dc0bba20052

📥 Commits

Reviewing files that changed from the base of the PR and between 7ccb4b1 and 3c140bb.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (45)
  • .github/actions/setup-python/action.yml
  • .github/workflows/lint.yml
  • .github/workflows/pytest.yml
  • .pre-commit-config.yml
  • docs/schema/cheatsheet.schema.json
  • pyproject.toml
  • pytest.ini
  • src/koalakeys/__init__.py
  • src/koalakeys/generate_cheatsheet.py
  • src/koalakeys/layouts/keyboard_layouts.yaml
  • src/koalakeys/layouts/system_mappings.yaml
  • src/koalakeys/logger.py
  • src/koalakeys/template_renderer.py
  • src/koalakeys/templates/base.html
  • src/koalakeys/templates/cheatsheets/assets/cheatsheets.css
  • src/koalakeys/templates/cheatsheets/cheatsheet-template.html
  • src/koalakeys/templates/cheatsheets/components/body.html
  • src/koalakeys/templates/cheatsheets/scripts/main.js
  • src/koalakeys/templates/index/assets/index.css
  • src/koalakeys/templates/index/components/body.html
  • src/koalakeys/templates/index/components/footer.html
  • src/koalakeys/templates/index/index_template.html
  • src/koalakeys/templates/index/scripts/main.js
  • src/koalakeys/themes/catppuccin.yaml
  • src/koalakeys/themes/dracula.yaml
  • src/koalakeys/themes/gruvbox.yaml
  • src/koalakeys/themes/nord.yaml
  • src/koalakeys/themes/rose-pine.yaml
  • src/koalakeys/themes/solarized.yaml
  • src/koalakeys/theming.py
  • src/koalakeys/validate_yaml.py
  • src/layouts/keyboard_layouts.yaml
  • src/layouts/system_mappings.yaml
  • src/templates/cheatsheets/assets/cheatsheets.css
  • src/templates/cheatsheets/cheatsheet-template.html
  • src/templates/index/assets/index.css
  • tests/__init__.py
  • tests/conftest.py
  • tests/test_browser.py
  • tests/test_generate_cheatsheet.py
  • tests/test_integration.py
  • tests/test_replace_shortcut_names.py
  • tests/test_template_renderer.py
  • tests/test_theming.py
  • tests/test_validate_yaml.py
💤 Files with no reviewable changes (6)
  • src/templates/index/assets/index.css
  • tests/init.py
  • src/layouts/keyboard_layouts.yaml
  • src/templates/cheatsheets/cheatsheet-template.html
  • src/layouts/system_mappings.yaml
  • src/templates/cheatsheets/assets/cheatsheets.css

Comment on lines +29 to +31
THEMES_DIR = PROJECT_ROOT / "themes"
STYLES_DIR = PROJECT_ROOT / "styles"
LAYOUTS_DIR = PACKAGE_DIR / "layouts"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Theme lookup path is inconsistent with the relocated package assets.

Line 29 points to PROJECT_ROOT / "themes", but this PR moves themes into the package namespace. That can cause resolve_theme(...) to miss theme files and make generate_html(...) return None on otherwise valid input.

💡 Proposed fix
-THEMES_DIR = PROJECT_ROOT / "themes"
+THEMES_DIR = PACKAGE_DIR / "themes"

Comment on lines +31 to +41
margin-bottom: 10px;
font-weight: 700;
font-size: 2.2rem;
position: absolute;
left: 50%;
right: 0;
margin: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 100vw;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

find . -name "cheatsheets.css" -type f

Repository: rtuszik/KoalaKeys

Length of output: 122


🏁 Script executed:

cat -n src/koalakeys/templates/cheatsheets/assets/cheatsheets.css | sed -n '25,50p'

Repository: rtuszik/KoalaKeys

Length of output: 776


🏁 Script executed:

cat -n src/koalakeys/templates/cheatsheets/assets/cheatsheets.css | sed -n '110,165p'

Repository: rtuszik/KoalaKeys

Length of output: 1438


🌐 Web query:

CSS word-wrap property deprecated MDN

💡 Result:

CSS word-wrap is not a separate modern property; it’s a legacy name/alias of overflow-wrap, so it is effectively deprecated in favor of overflow-wrap. MDN’s overflow-wrap documentation notes that the property was originally a nonstandard Microsoft extension called “word-wrap” and that it has since been renamed to overflow-wrap, with “word-wrap” being an alias. [1] The CSS Text Module Level 3 specification similarly states that UAs must treat word-wrap as a legacy name alias of overflow-wrap. [2] So: prefer overflow-wrap (e.g., overflow-wrap: anywhere / break-word) rather than word-wrap. [1][2]

Citations:


Remove redundant margin and deprecated word-wrap declarations.

The h1 rule has margin-bottom: 10px; on line 31 immediately overridden by margin: 0; on line 37. The .shortcut-key (lines 117–118) and .shortcut-description (lines 158–159) blocks both declare the legacy word-wrap alias alongside the modern overflow-wrap property. Remove the dead declarations to reduce lint noise and improve code clarity.

Suggested patch
 h1 {
 	color: var(--kk-accent);
 	text-align: center;
-	margin-bottom: 10px;
 	font-weight: 700;
 	font-size: 2.2rem;
 	position: absolute;
 	left: 50%;
 	right: 0;
 	margin: 0;
@@
 .shortcut-key {
@@
-	word-wrap: break-word;
 	overflow-wrap: break-word;
@@
 .shortcut-description {
@@
-	word-wrap: break-word;
 	overflow-wrap: break-word;
🧰 Tools
🪛 Stylelint (17.13.0)

[error] 37-37: Overridden property "margin-bottom" by shorthand "margin" (declaration-block-no-shorthand-property-overrides)

(declaration-block-no-shorthand-property-overrides)

Source: Linters/SAST tools

Comment on lines +99 to +110
#dark-mode-toggle {
background: none;
border: none;
cursor: pointer;
font-size: 24px;
color: var(--text);
transition: color 0.3s;
}

body.dark-mode #dark-mode-toggle {
color: var(--mocha-text);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n src/koalakeys/templates/index/assets/index.css | sed -n '95,115p'

Repository: rtuszik/KoalaKeys

Length of output: 546


🏁 Script executed:

cat -n src/koalakeys/templates/index/assets/index.css | head -50

Repository: rtuszik/KoalaKeys

Length of output: 1679


🏁 Script executed:

rg "(?:--text|--latte-text|:root)" src/koalakeys/templates/index/assets/index.css -A 2 -B 2

Repository: rtuszik/KoalaKeys

Length of output: 846


Use the defined --latte-text token for the toggle colour in light mode.

Line 104 references var(--text), which is not defined in the CSS variables. This causes the colour to depend on fallback or inheritance rather than the intended design token. Replace it with --latte-text to match the pattern used elsewhere in the stylesheet and the corresponding dark-mode rule.

Suggested patch
 `#dark-mode-toggle` {
 	background: none;
 	border: none;
 	cursor: pointer;
 	font-size: 24px;
-	color: var(--text);
+	color: var(--latte-text);
 	transition: color 0.3s;
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#dark-mode-toggle {
background: none;
border: none;
cursor: pointer;
font-size: 24px;
color: var(--text);
transition: color 0.3s;
}
body.dark-mode #dark-mode-toggle {
color: var(--mocha-text);
}
`#dark-mode-toggle` {
background: none;
border: none;
cursor: pointer;
font-size: 24px;
color: var(--latte-text);
transition: color 0.3s;
}
body.dark-mode `#dark-mode-toggle` {
color: var(--mocha-text);
}

Comment thread src/koalakeys/theming.py
Comment on lines +145 to +148
if key in RESERVED_KEYS:
if key in MODES and value:
modes[key] = {k: _validate_token_value(k, v) for k, v in value.items()}
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard mode blocks before iterating .items()

Line 147 can raise an uncaught exception when a theme defines light/dark as a non-mapping value. This bypasses ThemeError handling and can crash generation.

Suggested fix
         if key in RESERVED_KEYS:
             if key in MODES and value:
-                modes[key] = {k: _validate_token_value(k, v) for k, v in value.items()}
+                if not isinstance(value, dict):
+                    raise ThemeError(f"Theme mode '{key}' must be a mapping of token -> value")
+                modes[key] = {k: _validate_token_value(k, v) for k, v in value.items()}
             continue

Comment thread src/koalakeys/theming.py
Comment on lines +223 to +225
if narrowed is not None:
if not isinstance(narrowed, list) or not set(narrowed) <= set(MODES):
raise ThemeError(f"User theme '{name}': 'modes' must be a subset of {list(MODES)}")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Harden modes narrowing type checks

Line 224 can throw TypeError for unhashable entries (for example nested lists) before you raise ThemeError. Validate element types explicitly first.

Suggested fix
     if narrowed is not None:
-        if not isinstance(narrowed, list) or not set(narrowed) <= set(MODES):
+        if (
+            not isinstance(narrowed, list)
+            or not all(isinstance(mode, str) for mode in narrowed)
+            or not set(narrowed) <= set(MODES)
+        ):
             raise ThemeError(f"User theme '{name}': 'modes' must be a subset of {list(MODES)}")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if narrowed is not None:
if not isinstance(narrowed, list) or not set(narrowed) <= set(MODES):
raise ThemeError(f"User theme '{name}': 'modes' must be a subset of {list(MODES)}")
if narrowed is not None:
if (
not isinstance(narrowed, list)
or not all(isinstance(mode, str) for mode in narrowed)
or not set(narrowed) <= set(MODES)
):
raise ThemeError(f"User theme '{name}': 'modes' must be a subset of {list(MODES)}")

Comment on lines +141 to +150
validators = [
validate_required_keys,
validate_title,
validate_render_options,
validate_styling,
validate_layout,
validate_shortcuts,
]
results = [validator(data) for validator in validators]
is_valid = all(results)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add a top-level mapping guard before running validator list

The new aggregated execution can crash on non-object YAML (for example a list), because validators like validate_render_options call data.get(...). Fail fast with a type check before invoking validators.

Suggested fix
     if data is None:
         logger.error(f"Empty YAML file: {file_path}")
         return False
+    if not isinstance(data, dict):
+        logger.error(f"Top-level YAML must be a mapping/object: {file_path}")
+        return False
 
     validators = [
         validate_required_keys,
         validate_title,
         validate_render_options,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
validators = [
validate_required_keys,
validate_title,
validate_render_options,
validate_styling,
validate_layout,
validate_shortcuts,
]
results = [validator(data) for validator in validators]
is_valid = all(results)
if data is None:
logger.error(f"Empty YAML file: {file_path}")
return False
if not isinstance(data, dict):
logger.error(f"Top-level YAML must be a mapping/object: {file_path}")
return False
validators = [
validate_required_keys,
validate_title,
validate_render_options,
validate_styling,
validate_layout,
validate_shortcuts,
]
results = [validator(data) for validator in validators]
is_valid = all(results)

Comment thread tests/test_browser.py
class TestCheatsheetInBrowser:
def test_loads_without_console_errors(self, page):
assert page.console_errors == [], f"unexpected JS errors: {page.console_errors}"
assert "Full Featured Test" in page.title() or page.locator("h1").count() >= 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix the always-true fallback in the page title assertion.

Line 56 uses page.locator("h1").count() >= 0, which always passes and can hide a broken render path.

Proposed fix
-        assert "Full Featured Test" in page.title() or page.locator("h1").count() >= 0
+        assert "Full Featured Test" in page.title() or page.locator("h1").count() > 0
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
assert "Full Featured Test" in page.title() or page.locator("h1").count() >= 0
assert "Full Featured Test" in page.title() or page.locator("h1").count() > 0

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to GitHub limitations.

⚠️ Outside diff range comments (2)

🟠 Major · Align the package version with the 1.0.0 release target. · pyproject.toml:3

pyproject.toml:3
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Align the package version with the 1.0.0 release target.

A build from this PR will declare version 0.6.0 in its package metadata. Set version to 1.0.0, or align the release target with 0.6.0, before publishing.

🟠 Major · Confine custom_css to STYLES_DIR. · generate_cheatsheet.py:142

src/koalakeys/generate_cheatsheet.py:142
🔒 Security & Privacy | 🛡️ Detected with Advanced Tier | 🟠 Major | ⚡ Quick win

Path Traversal

Exploitability: Moderate
CWE: CWE-22 — Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

Confine custom_css to STYLES_DIR.

If an attacker can supply a cheatsheet, custom_css can contain an absolute path or .. segments. STYLES_DIR / filename can then read any readable file outside styles/, and the content is inserted into the generated HTML. Resolve the root and candidate paths, then reject candidates outside the resolved STYLES_DIR before calling read_text.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: c1f8a17f-2c12-4f4f-a227-b9c9220a260a

📥 Commits

Reviewing files that changed from the base of the PR and between 3c140bb and 96f3c40.

⛔ Files ignored due to path filters (1)
  • assets/images/KoalaKeys_Example.png is excluded by !**/*.png
📒 Files selected for processing (12)
  • README.md
  • pyproject.toml
  • src/koalakeys/cli.py
  • src/koalakeys/generate_cheatsheet.py
  • src/koalakeys/scaffold/__init__.py
  • src/koalakeys/scaffold/example.yaml
  • src/koalakeys/theming.py
  • src/koalakeys/validate_yaml.py
  • tests/test_cli.py
  • tests/test_generate_cheatsheet.py
  • tests/test_scaffold.py
  • yaml_cheatsheet_spec.md
💤 Files with no reviewable changes (1)
  • src/koalakeys/validate_yaml.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/koalakeys/theming.py

Included review availability: Your plan provides up to 2 included reviews per hour; 1 remains after this review.

Comment thread README.md
KoalaKeys generates and organizes portable, interactive HTML cheat sheets for keyboard shortcuts. It's designed for developers, designers, and power users who want to keep their essential shortcuts easily accessible.

> **Quick Start**: To create a cheat sheet, add a YAML file to the `cheatsheets` directory and run `python src/generate_cheatsheet.py`. For detailed YAML formatting instructions, see the [YAML Cheat Sheet Specification Guide](yaml_cheatsheet_spec.md).
> **Quick Start**: Run `uvx koalakeys init` to scaffold a project, add or edit YAML files in its `cheatsheets/` directory, then run `koalakeys generate`. For detailed YAML formatting instructions, see the [YAML Cheat Sheet Specification Guide](yaml_cheatsheet_spec.md).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make the quick-start directory explicit.

uvx koalakeys init creates ./koalakeys by default, while generate reads cheatsheets/ from the current directory. The documented sequence fails if the user runs koalakeys generate from the parent directory. Add cd koalakeys before generation, and use uvx koalakeys generate or install the tool before using the bare command.

Comment thread src/koalakeys/cli.py
print(f"Validating {path}...")
if not validate_yaml(path):
all_valid = False
for warning in lint_yaml(path):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Check that the validation path is a file before linting it.

cmd_validate calls lint_yaml(path) after validate_yaml(path) reports failure. For a missing path or directory, lint_yaml can raise an uncaught FileNotFoundError or IsADirectoryError. Check that path is a file before calling lint_yaml, so the command returns status 1 without a traceback.

Comment on lines +260 to +262
if not cheatsheets:
print("No valid cheatsheets were generated due to errors.")
return 1

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Return failure when any cheatsheet generation fails.

If one YAML file fails and another succeeds, cheatsheets is non-empty and Line 276 returns 0. The command then reports success while omitting the failed cheatsheet from the index. Track per-file failures and return a non-zero status when any selected file fails.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant