Skip to content

Conversation

@smoser
Copy link
Contributor

@smoser smoser commented Nov 5, 2025

draft. playing with a drop in replacement for apko.
the apko-as-apk works somewhat but claude is having trouble with scripts.

smoser and others added 6 commits December 12, 2025 13:00
This fixes a bug in dirFS where WriteFile would cache an empty buffer
in the memory overlay even though it wrote the correct data to disk.
This caused subsequent ReadFile operations to return zeros instead of
the actual file content.

Root cause:
- WriteFile used conditional logic where memContent was left empty when
  createOnDisk(name) returned true
- The empty buffer was then stored in the overlay via
  f.overrides.WriteFile(name, memContent, mode)
- ReadFile would return this cached empty buffer when
  caseSensitiveOnDisk returned false

Impact:
- Any code that wrote a file and then read it back through dirFS could
  receive zeros instead of actual data
- This particularly affected updateScriptsTar in pkg/apk/apk/installed.go
  which would corrupt scripts.tar files during package installation

Solution:
- Always cache the actual data in the memory overlay, not an empty buffer
- Simplified WriteFile by removing memContent variable and conditional
- Updated comment to clarify the new behavior

Added comprehensive unit tests to verify:
- Basic write/read cycles work correctly
- Multiple writes/reads maintain data integrity
- Stat calls don't affect caching behavior
- OpenFile/Write/Close patterns work correctly
- The exact updateScriptsTar pattern preserves data

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Implements a new apko-as-apk binary that provides APK-compatible
package management using apko's existing functionality. This allows
apko to operate directly on filesystem trees including the root
filesystem, rather than just building container images.

Implemented commands:
- add: Add packages to the system (partially functional, has issues
  with install scripts)
- update: Update repository indexes (fully functional)
- info: Display package information (fully functional)

The tool defaults to operating on root=/ like the native apk command,
but supports --root/-p for alternate filesystem roots.

Architecture leverages existing pkg/apk/apk implementation, requiring
no new APK parsing or installation code.

Known issue: The add command currently fails for packages with install
scripts due to script extraction handling that needs investigation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Adds comprehensive test coverage for the apko-as-apk binary including:

Unit tests (internal/cli/apkcompat/apkcompat_test.go):
- Repository file parsing with comments and blank lines
- Command-line repository handling
- Key installation with various directory states
- Package info formatting
- Table-driven tests for helper functions

Container integration tests (internal/cli/apkcompat/container_test.go):
- Compare apk and apko-as-apk info command output
- Verify update command behavior
- Test various command flags and options
- Uses containerTest build tag to separate from fast unit tests
- Automatically builds and tears down Docker containers

Makefile targets:
- make test-apko-as-apk: Run fast unit tests (~0.007s)
- make test-apko-as-apk-container: Run integration tests (~11.5s)

All tests pass successfully. Container tests require Docker to be running.

Updated README with testing documentation covering unit tests, container
tests, and manual testing procedures.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…nstallation

Fixes multiple issues preventing apko-as-apk from installing packages that
need to replace busybox symlinks (e.g., grep, egrep, fgrep):

1. Allow overwriting files not tracked in installedFiles (busybox symlinks)
2. Create scripts.tar if it doesn't exist (for existing root filesystems)
3. Fix layered filesystem to properly remove symlinks from disk
4. Remove symlinks before creating regular files in dirFS.OpenFile

Also adds comprehensive tests:
- Unit test for overwriting untracked files
- Container test verifying grep installation over busybox symlinks

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Fixes issue where packages like coreutils couldn't install their symlinks
because busybox symlinks already existed at those paths.

When installing a symlink, if a symlink or file already exists at that path
with a different target, remove it first before creating the new symlink.

This handles cases like:
- /usr/bin/[ pointing to /bin/busybox being replaced with -> coreutils
- /usr/bin/test pointing to /bin/busybox being replaced with -> coreutils

Adds container test for coreutils installation to verify symlink replacement.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…adding new packages

This fixes a bug where apko-as-apk add would fail when the system had
packages installed from repositories that are no longer accessible.

Problem:
When running `apko-as-apk add <package>` in a container with packages
from private or unavailable repositories (e.g., chainguard-baselayout
from cgr.dev/chainguard-private), the command would fail with:
"failed to resolve world: nothing provides <unavailable-package>"

This occurred because the add command would:
1. Read all packages from /etc/apk/world (including already-installed ones)
2. Add the new package to world
3. Call ResolveWorld() which tried to re-resolve ALL packages
4. Fail when it couldn't find already-installed packages in current repos

Example failure:
  docker run cgr.dev/chainguard-private/chainguard-base:latest \
    apko-as-apk add grep
  # Error: nothing provides "chainguard-baselayout"

Solution:
Modified internal/cli/apkcompat/add.go to:
1. Get the list of already-installed packages before resolving
2. Filter the world file to only include packages NOT already installed
3. Only resolve and install packages that are actually new
4. Call InstallPackages() directly instead of FixateWorld() to avoid
   re-resolving the entire world

This matches the behavior of the real `apk` command, which doesn't
attempt to re-resolve packages that are already installed.

Testing:
- Added comprehensive unit tests in add_test.go
- Verified fix works with both chainguard-base and wolfi-base containers
- All existing tests pass

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@smoser
Copy link
Contributor Author

smoser commented Dec 12, 2025

I made some progress. There is a bug in it when adding packages with a scriptlet the /lib/apk/db/scripts.tar file becomes corrupted and 'apk info' fails.

that can be reproduced with:

docker run --rm -it --entrypoint=/bin/sh   \
      --mount=type=bind,source=$PWD/apko-as-apk,destination=/usr/bin/apko-as-apk  \
      cgr.dev/chainguard/wolfi-base:latest   \
     -c 'apko-as-apk add coreutils && apk info'

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