API-Docker
view release on metacpan or search on metacpan
API-Docker-*
.build
# Claude Code â commit: skills/, agents/, hooks/, settings.json
# Ignore: local overrides, credentials, session data
.claude/*.local.*
.claude/local/
.claude/.credentials.json
.claude/statsig/
.claude/todos/
.claude/projects/
2. **Use `mcp__firecrawl__firecrawl_scrape`** over `WebFetch` for fetching
page content.
3. **Use `context7` for library docs** (CPAN, npm, etc.) â *except* this
distribution itself. For `API::Docker` always read the local source
under `lib/`, never context7.
4. **Untracked files that are not in `.gitignore` belong in the commit.**
`.gitignore` is the source of truth. Only obvious secrets
(`.env`, credentials) are excluded â and even then warn, don't silently
drop them.
5. **Auto-Memory is for personal/user preferences only.** Project
conventions belong in this `CLAUDE.md` or in a skill, never in
auto-memory.
6. **Load the `perl-core` skill before editing any Perl** in this
workspace. It encodes Getty's house rules; the rules below are the
TL;DR.
Revision history for API-Docker
0.002 2026-05-17 05:36:20Z
- HTTP role: `_request` now accepts a `headers => {}` option to set
extra HTTP request headers. Headers are sanitised against CR/LF
injection. Used by `images->push` to send `X-Registry-Auth`, and
available to any caller that needs custom headers.
- `images->push` now always sends an `X-Registry-Auth` header â the
Docker Engine refuses pushes without it (`HTTP 400: missing
X-Registry-Auth: invalid X-Registry-Auth header: EOF`). A new `auth`
option accepts a hashref of credentials (`username`, `password`,
`serveraddress`, or `identitytoken`) which is JSON-encoded and
base64url-wrapped per the Docker Engine spec. Without `auth` the
header carries an empty JSON object so unauthenticated/public
pushes succeed where they previously failed at the HTTP layer.
0.001 2026-04-29 00:40:43Z
- Initial release as API::Docker
- Docker Engine API client with Unix socket and TCP support
- Auto-negotiate API version from daemon
- Container, Image, Network, Volume, System, and Exec APIs
lib/API/Docker/API/Images.pm view on Meta::CPAN
$images->push('myrepo/nginx', auth => {
username => 'me',
password => 'secret',
serveraddress => 'https://index.docker.io/v1/',
});
Push an image to a registry. Optionally specify C<tag>.
The Docker Engine requires an C<X-Registry-Auth> header on every push,
even for anonymous attempts; the header is always sent. Pass C<auth> as
a hashref of credentials (typical keys: C<username>, C<password>,
C<serveraddress>, or C<identitytoken>), or as a pre-encoded base64 string.
Without C<auth> the header carries an empty JSON object.
=head2 tag
$images->tag('nginx:latest', repo => 'myrepo/nginx', tag => 'v1');
Tag an image with a new repository and/or tag name.
=head2 remove
t/images_push_auth.t view on Meta::CPAN
return decode_base64($s);
}
subtest 'empty/undef auth -> base64url("{}")' => sub {
my $hdr = API::Docker::API::Images::_build_registry_auth_header(undef);
ok length($hdr), 'header is non-empty for undef';
is_deeply(decode_json(b64url_decode($hdr)), {},
'decodes to empty JSON object');
};
subtest 'hashref auth -> JSON-encoded credentials' => sub {
my $auth = {
username => 'me',
password => 'secret',
serveraddress => 'https://index.docker.io/v1/',
};
my $hdr = API::Docker::API::Images::_build_registry_auth_header($auth);
is_deeply(decode_json(b64url_decode($hdr)), $auth,
'header roundtrips through base64url + JSON');
};
t/images_push_auth.t view on Meta::CPAN
tag => 'user',
);
is $captured->{method}, 'POST', 'POST issued';
like $captured->{path}, qr{^/images/raudssus/karr:user/push}, 'push path';
ok exists $captured->{headers}{'X-Registry-Auth'},
'X-Registry-Auth header present';
is_deeply(
decode_json(b64url_decode($captured->{headers}{'X-Registry-Auth'})),
{ username => 'u', password => 'p' },
'header decodes to passed credentials',
);
is $captured->{params}{tag}, 'user', 'tag param present';
};
done_testing;
( run in 0.487 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )