File: //scripts/rebuild_api_readonly_cache
#!/usr/local/cpanel/3rdparty/bin/perl
# Copyright 2026 WebPros International, LLC
# All rights reserved.
# copyright@cpanel.net http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited.
package scripts::rebuild_api_readonly_cache;
use strict;
use warnings;
use Getopt::Long qw(:config auto_help);
use Pod::Usage;
use Cpanel::API::ReadOnlyMap::PluginCache ();
=head1 NAME
scripts/rebuild_api_readonly_cache - Rebuild the plugin read-only API overlay cache
=head1 SYNOPSIS
scripts/rebuild_api_readonly_cache [--quiet]
Regenerates C</var/cpanel/caches/api_readonly_plugins.cache> wholesale from
every installed plugin's C</var/cpanel/plugins/*/api-readonly.uapi.yaml>
manifest. This is the read-only classification overlay that
L<Cpanel::API::ReadOnly> consults (alongside the compiled core map) to enforce
read-only API token scope for plugin UAPI methods.
Invoked from each plugin's install/upgrade (C<pkg.postinst>) and removal
(C<pkg.postrm>) scriptlet, and once per cPanel update via the
C<install/RebuildApiReadonlyCache.pm> task. Safe to run any time (idempotent).
Must run as root.
The per-update task closes a deployment-ordering gap: a plugin installed before
this script existed ran a guarded scriptlet that no-op'd, so its read-only
methods would otherwise stay denied (fail-closed) until a reinstall. The update
task rebuilds from all installed manifests so they register on the next update.
The rebuild is fail-closed: a malformed or unreadable plugin manifest is skipped
with a warning, never aborting the rebuild, and a manifest entry that collides
with a core classification is ignored (core-wins). The overlay only ever adds
read-only allowances; it can never widen write access.
=head1 OPTIONS
=over 4
=item B<--quiet>
Suppress the summary line on success.
=item B<--help>
Show this help and exit.
=back
=cut
__PACKAGE__->script(@ARGV) if !caller;
sub script {
my ( $pkg, @argv ) = @_;
local @ARGV = @argv;
my $quiet = 0;
GetOptions( 'quiet' => \$quiet ) or pod2usage(2);
if ( $> != 0 ) {
die "rebuild_api_readonly_cache must run as root\n";
}
my $overlay = Cpanel::API::ReadOnlyMap::PluginCache->rebuild();
if ( !$quiet ) {
printf "Wrote %s: %d plugin read-only entries\n",
$Cpanel::API::ReadOnlyMap::PluginCache::CACHE_PATH,
scalar keys %$overlay;
}
return 0;
}
1;