Bugzilla – Attachment 191345 Details for
Bug 37025
Add CLI tool to generate/delete api keys for a given patron on a Koha instance
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 37025: (QA follow-up) Use standard koha- script invocation pattern
Bug-37025-QA-follow-up-Use-standard-koha--script-i.patch (text/plain), 19.21 KB, created by
Paul Derscheid
on 2026-01-13 10:05:41 UTC
(
hide
)
Description:
Bug 37025: (QA follow-up) Use standard koha- script invocation pattern
Filename:
MIME Type:
Creator:
Paul Derscheid
Created:
2026-01-13 10:05:41 UTC
Size:
19.21 KB
patch
obsolete
>From f986c2b8b2502d1d67aea08cdf19f73ed0e76d34 Mon Sep 17 00:00:00 2001 >From: Paul Derscheid <paul.derscheid@lmscloud.de> >Date: Tue, 13 Jan 2026 10:54:25 +0100 >Subject: [PATCH] Bug 37025: (QA follow-up) Use standard koha- script > invocation pattern > >- Add Koha::Perl::Instance module for shared environment setup logic >- Script now takes instance name as last argument >- Re-exec with proper environment setup (PERL5LIB, KOHA_CONF) >- Pass arguments directly via exec() to avoid shell quoting issues >- Support both package and git installs >- Use Koha::Script to set CLI interface for proper audit logging >- Add APIKEY module to log viewer >- Add translation for GENERATE action >- Usage: sudo koha-api-keys [options] instancename >- Update POD and DocBook XML documentation > >The new Koha::Perl::Instance module provides reusable functions for >other perl-based debian scripts that need to run in a Koha environment: >- in_koha_env(): Check if already running in Koha environment >- get_instance_perl5lib(): Get PERL5LIB for an instance >- reexec_in_koha_env(): Re-execute script with proper environment > >Test plan: >NOTE: For testing, copy files first: > cp debian/scripts/koha-api-keys /usr/sbin/ > mkdir -p /usr/share/koha/bin/Koha/Perl > cp debian/scripts/Koha/Perl/Instance.pm /usr/share/koha/bin/Koha/Perl/ > >1. Test help output: > sudo koha-api-keys --help > >2. Test API key generation (with spaces in description): > sudo koha-api-keys --generate --description 'Test key' --borrowernumber 51 instancename > => Should output Client ID and Client Secret > >3. Test interactive deletion: > sudo koha-api-keys --delete instancename > => Should prompt for Client ID, then delete > >4. Test scripted deletion: > sudo koha-api-keys --delete --client-id CLIENT_ID instancename > => Should delete without prompting > >5. Test error handling: > sudo koha-api-keys --generate --description test instancename > => Should show error about missing --borrowernumber > >6. Test invalid instance: > sudo koha-api-keys --generate --description test --borrowernumber 51 nonexistent > => Should show error about instance not existing > >7. Verify audit logging in log viewer: > - Go to Tools > Log viewer > - Select "API keys" module > - Should see GENERATE and DELETE actions with interface "Command-line" > >8. Verify DocBook XML validation: > prove -v xt/verify-debian-docbook.t >--- > debian/docs/koha-api-keys.xml | 26 +-- > debian/koha-common.install | 1 + > debian/koha-core.install | 1 + > debian/scripts/Koha/Perl/Instance.pm | 197 ++++++++++++++++++ > debian/scripts/koha-api-keys | 45 ++-- > .../prog/en/includes/action-logs.inc | 4 + > .../prog/en/modules/tools/viewlog.tt | 2 +- > 7 files changed, 249 insertions(+), 27 deletions(-) > create mode 100644 debian/scripts/Koha/Perl/Instance.pm > >diff --git a/debian/docs/koha-api-keys.xml b/debian/docs/koha-api-keys.xml >index 62bb2458f2c..75da7328d7c 100644 >--- a/debian/docs/koha-api-keys.xml >+++ b/debian/docs/koha-api-keys.xml >@@ -29,19 +29,21 @@ > > <refsynopsisdiv> > <cmdsynopsis> >- <command>sudo koha-shell</command> >- <arg choice="req"><option>-c</option> "koha-api-keys <option>--generate</option> <option>--description</option> <replaceable>description</replaceable> <option>--borrowernumber</option> <replaceable>borrowernumber</replaceable>"</arg> >+ <command>sudo koha-api-keys</command> >+ <arg choice="req"><option>--generate</option></arg> >+ <arg choice="req"><option>--description</option> <replaceable>description</replaceable></arg> >+ <arg choice="req"><option>--borrowernumber</option> <replaceable>borrowernumber</replaceable></arg> > <arg choice="req"><replaceable>instancename</replaceable></arg> > </cmdsynopsis> > <cmdsynopsis> >- <command>sudo koha-shell</command> >- <arg choice="req"><option>-c</option> "koha-api-keys <option>--delete</option> [<option>--client-id</option> <replaceable>client_id</replaceable>]"</arg> >+ <command>sudo koha-api-keys</command> >+ <arg choice="req"><option>--delete</option></arg> >+ <arg choice="opt"><option>--client-id</option> <replaceable>client_id</replaceable></arg> > <arg choice="req"><replaceable>instancename</replaceable></arg> > </cmdsynopsis> > <cmdsynopsis> >- <command>sudo koha-shell</command> >- <arg choice="req"><option>-c</option> "koha-api-keys <option>--help</option>"</arg> >- <arg choice="req"><replaceable>instancename</replaceable></arg> >+ <command>sudo koha-api-keys</command> >+ <arg choice="req"><option>--help</option></arg> > </cmdsynopsis> > </refsynopsisdiv> > >@@ -51,7 +53,7 @@ > The <command>koha-api-keys</command> script allows administrators to generate or delete API keys associated with specific Koha patrons. These API keys can be used for authorized programmatic access to the Koha system. > </para> > <para> >- As this tool requires administrative privileges and access to the Koha environment, it must be run using <command>sudo</command> and the <command>koha-shell</command> wrapper as shown in the synopsis. >+ The instance name must be provided as the last argument. The script will automatically set up the Koha environment and run as the instance user. > </para> > </refsect1> > >@@ -100,16 +102,16 @@ > <refsect1> > <title>Examples</title> > <para>Generate a new API key for patron '123' with the description 'Test API access':</para> >- <screen>$ sudo koha-shell -c "koha-api-keys --generate --description 'Test API access' --borrowernumber 123" instancename</screen> >+ <screen>$ sudo koha-api-keys --generate --description 'Test API access' --borrowernumber 123 instancename</screen> > > <para>Delete an existing API key (interactive):</para> >- <screen>$ echo "CLIENT_ID" | sudo koha-shell -c "koha-api-keys --delete" instancename</screen> >+ <screen>$ sudo koha-api-keys --delete instancename</screen> > > <para>Delete an existing API key (scripted):</para> >- <screen>$ sudo koha-shell -c "koha-api-keys --delete --client-id a1b2c3d4-e5f6-7890-abcd-ef1234567890" instancename</screen> >+ <screen>$ sudo koha-api-keys --delete --client-id a1b2c3d4-e5f6-7890-abcd-ef1234567890 instancename</screen> > > <para>Display help information:</para> >- <screen>$ sudo koha-shell -c "koha-api-keys --help" instancename</screen> >+ <screen>$ sudo koha-api-keys --help</screen> > </refsect1> > </refentry> > </article> >diff --git a/debian/koha-common.install b/debian/koha-common.install >index 23c9b719f1e..344db89cc4f 100644 >--- a/debian/koha-common.install >+++ b/debian/koha-common.install >@@ -7,6 +7,7 @@ debian/unavailable.html usr/share/koha/intranet/htdocs > debian/unavailable.html usr/share/koha/opac/htdocs > debian/templates/* etc/koha > debian/scripts/koha-functions.sh usr/share/koha/bin >+debian/scripts/Koha usr/share/koha/bin > debian/scripts/koha-api-keys usr/sbin > debian/scripts/koha-create usr/sbin > debian/scripts/koha-create-dirs usr/sbin >diff --git a/debian/koha-core.install b/debian/koha-core.install >index 2b8c0f4646b..fdd36ec7db7 100644 >--- a/debian/koha-core.install >+++ b/debian/koha-core.install >@@ -7,6 +7,7 @@ debian/unavailable.html usr/share/koha/intranet/htdocs > debian/unavailable.html usr/share/koha/opac/htdocs > debian/templates/* etc/koha > debian/scripts/koha-functions.sh usr/share/koha/bin >+debian/scripts/Koha usr/share/koha/bin > debian/scripts/koha-create usr/sbin > debian/scripts/koha-create-dirs usr/sbin > debian/scripts/koha-disable usr/sbin >diff --git a/debian/scripts/Koha/Perl/Instance.pm b/debian/scripts/Koha/Perl/Instance.pm >new file mode 100644 >index 00000000000..57aeb2fce9a >--- /dev/null >+++ b/debian/scripts/Koha/Perl/Instance.pm >@@ -0,0 +1,197 @@ >+package Koha::Perl::Instance; >+ >+# Koha::Perl::Instance - Shared Perl utilities for koha-* debian scripts >+# Copyright 2026 LMSCloud GmbH >+# >+# This program is free software: you can redistribute it and/or modify >+# it under the terms of the GNU General Public License as published by >+# the Free Software Foundation, either version 3 of the License, or >+# (at your option) any later version. >+# >+# This program is distributed in the hope that it will be useful, >+# but WITHOUT ANY WARRANTY; without even the implied warranty of >+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+# GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License >+# along with this program. If not, see <http://www.gnu.org/licenses/>. >+ >+use Modern::Perl; >+ >+use Exporter qw( import ); >+our @EXPORT_OK = qw( in_koha_env get_instance_perl5lib reexec_in_koha_env ); >+ >+=head1 NAME >+ >+Koha::Perl::Instance - Shared utilities for Koha debian scripts >+ >+=head1 SYNOPSIS >+ >+ use lib '/usr/share/koha/bin'; >+ use Koha::Perl::Instance qw( in_koha_env reexec_in_koha_env ); >+ >+ # Re-exec with Koha environment if not already set up >+ if ( !in_koha_env() ) { >+ my $instance = pop @ARGV; >+ reexec_in_koha_env({ instance => $instance, argv => \@ARGV }); >+ } >+ >+=head1 DESCRIPTION >+ >+This module provides shared utilities for Perl-based koha-* debian scripts >+that need to run within a Koha instance's environment. >+ >+=head1 FUNCTIONS >+ >+=head2 in_koha_env >+ >+ if ( in_koha_env() ) { ... } >+ >+Returns true if the script is running within a Koha environment >+(i.e., KOHA_CONF is set). >+ >+=cut >+ >+sub in_koha_env { >+ return defined $ENV{KOHA_CONF} && $ENV{KOHA_CONF} ne q{}; >+} >+ >+=head2 get_instance_perl5lib >+ >+ my $perl5lib = get_instance_perl5lib($instance); >+ >+Returns the appropriate PERL5LIB path for the given Koha instance. >+Handles both package installs and git/dev installs. >+ >+=cut >+ >+sub get_instance_perl5lib { >+ my ($instance) = @_; >+ >+ my $koha_conf = "/etc/koha/sites/$instance/koha-conf.xml"; >+ my $perl5lib; >+ >+ # Check if this is a git install >+ my $is_git = `bash -c '. /usr/share/koha/bin/koha-functions.sh; if is_git_install $instance; then echo 1; fi'`; >+ chomp $is_git; >+ >+ if ($is_git) { >+ >+ # For git installs, get path from koha-conf.xml >+ $perl5lib = `xmlstarlet sel -t -v 'yazgfs/config/intranetdir' $koha_conf 2>/dev/null`; >+ chomp $perl5lib; >+ $perl5lib = "$perl5lib:$perl5lib/lib" if $perl5lib; >+ } >+ >+ if ( !$perl5lib ) { >+ >+ # Fall back to system default >+ $perl5lib = `grep "^PERL5LIB=" /etc/default/koha-common 2>/dev/null`; >+ chomp $perl5lib; >+ $perl5lib =~ s/^PERL5LIB=\s*//; >+ $perl5lib =~ s/^"//; >+ $perl5lib =~ s/"$//; >+ } >+ >+ return $perl5lib; >+} >+ >+=head2 reexec_in_koha_env >+ >+ reexec_in_koha_env({ >+ instance => $instance, >+ argv => \@ARGV, >+ script => $0, >+ }); >+ >+Re-executes the current script with the proper Koha environment set up. >+This function does not return on success. >+ >+Arguments are passed directly to exec() without shell interpolation, >+avoiding quoting issues. >+ >+Parameters: >+ >+=over 4 >+ >+=item instance >+ >+The Koha instance name (required). >+ >+=item argv >+ >+Array ref of arguments to pass to the re-executed script (default: current @ARGV). >+ >+=item script >+ >+Path to the script to execute (default: $0). >+ >+=back >+ >+Dies with an error message if: >+ >+=over 4 >+ >+=item * instance is not provided >+ >+=item * instance does not exist >+ >+=item * exec fails >+ >+=back >+ >+=cut >+ >+sub reexec_in_koha_env { >+ my ($args) = @_; >+ >+ my $instance = $args->{instance}; >+ my $argv = $args->{argv} // \@ARGV; >+ my $script = $args->{script} // $0; >+ >+ die "Usage: sudo $0 [options] instancename\n" unless $instance; >+ die "Usage: sudo $0 [options] instancename\n" if $instance =~ /^-/; >+ die "Error: Koha instance '$instance' does not exist.\n" >+ unless -e "/etc/koha/sites/$instance"; >+ >+ my $perl5lib = get_instance_perl5lib($instance); >+ my $koha_conf = "/etc/koha/sites/$instance/koha-conf.xml"; >+ >+ exec( >+ '/usr/bin/sudo', '-u', "$instance-koha", '-H', >+ 'env', "PERL5LIB=$perl5lib", "KOHA_CONF=$koha_conf", >+ '/usr/bin/perl', $script, @{$argv} >+ ); >+ die "Failed to exec: $!\n"; >+} >+ >+1; >+ >+__END__ >+ >+=head1 AUTHOR >+ >+Paul Derscheid <paul.derscheid@lmscloud.de> >+ >+=head1 COPYRIGHT >+ >+Copyright LMSCloud GmbH >+ >+=head1 LICENSE >+ >+This file is part of Koha. >+ >+Koha is free software; you can redistribute it and/or modify it >+under the terms of the GNU General Public License as published by >+the Free Software Foundation; either version 3 of the License, or >+(at your option) any later version. >+ >+Koha is distributed in the hope that it will be useful, but >+WITHOUT ANY WARRANTY; without even the implied warranty of >+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >+GNU General Public License for more details. >+ >+You should have received a copy of the GNU General Public License >+along with Koha; if not, see <http://www.gnu.org/licenses>. >+ >+=cut >diff --git a/debian/scripts/koha-api-keys b/debian/scripts/koha-api-keys >index cbae068a13d..7bb8652c51e 100755 >--- a/debian/scripts/koha-api-keys >+++ b/debian/scripts/koha-api-keys >@@ -2,7 +2,7 @@ > > # koha-api-keys: generate or delete API keys for a given patron and > # Koha instance. >-# Copyright 2024 LMSCloud GmbH >+# Copyright 2026 LMSCloud GmbH > # > # This program is free software: you can redistribute it and/or modify > # it under the terms of the GNU General Public License as published by >@@ -21,10 +21,27 @@ use Modern::Perl; > use Getopt::Long qw( GetOptions ); > use Pod::Usage qw( pod2usage ); > >-use Koha::Script; >-use Koha::ApiKeys; >-use Koha::Patrons; >-use C4::Log qw( logaction ); >+use lib '/usr/share/koha/bin'; >+use Koha::Perl::Instance qw( in_koha_env reexec_in_koha_env ); >+ >+# Handle --help before re-exec (doesn't need Koha environment) >+if ( grep { $_ eq '--help' || $_ eq '-h' } @ARGV ) { >+ pod2usage(1); >+} >+ >+# If not in Koha environment, re-exec with proper environment >+if ( !in_koha_env() ) { >+ my $instance = pop @ARGV; >+ reexec_in_koha_env( { instance => $instance, argv => \@ARGV } ); >+} >+ >+# Now in Koha environment - load modules at runtime >+require Koha::Script; >+Koha::Script->import(); # Set CLI interface for proper audit logging >+require Koha::ApiKeys; >+require Koha::Patrons; >+require C4::Log; >+C4::Log->import('logaction'); > > my $generate; > my $delete; >@@ -143,11 +160,11 @@ koha-api-keys - Generate or delete API keys for specified patrons > > =head1 SYNOPSIS > >-sudo koha-shell -c "koha-api-keys --generate --description DESCRIPTION --borrowernumber BORROWERNUMBER" instancename >+sudo koha-api-keys --generate --description DESCRIPTION --borrowernumber BORROWERNUMBER instancename > >-sudo koha-shell -c "koha-api-keys --delete [--client-id CLIENT_ID]" instancename >+sudo koha-api-keys --delete [--client-id CLIENT_ID] instancename > >-sudo koha-shell -c "koha-api-keys --help" instancename >+sudo koha-api-keys --help > > =head1 OPTIONS > >@@ -183,8 +200,8 @@ Display this help message. > > This script lets you generate or delete API keys for specified patrons in Koha. > >-As this tool requires administrative privileges and access to the Koha environment, >-it must be run using sudo and koha-shell wrapper as shown in the synopsis. >+The instance name must be provided as the last argument. The script will >+automatically set up the Koha environment and run as the instance user. > > For generating keys, you must provide both a description and a borrower number. > For deleting keys, you can provide the client ID via --client-id or be prompted interactively. >@@ -192,17 +209,17 @@ For deleting keys, you can provide the client ID via --client-id or be prompted > =head1 EXAMPLES > > Generate an API key: >- sudo koha-shell -c "koha-api-keys --generate --description 'Test API access' --borrowernumber 123" instancename >+ sudo koha-api-keys --generate --description 'Test API access' --borrowernumber 123 instancename > > Delete an API key (interactive): >- echo "CLIENT_ID" | sudo koha-shell -c "koha-api-keys --delete" instancename >+ sudo koha-api-keys --delete instancename > > Delete an API key (scripted): >- sudo koha-shell -c "koha-api-keys --delete --client-id a1b2c3d4-e5f6-7890-abcd-ef1234567890" instancename >+ sudo koha-api-keys --delete --client-id a1b2c3d4-e5f6-7890-abcd-ef1234567890 instancename > > =head1 AUTHOR > >-Koha Development Team >+Paul Derscheid <paul.derscheid@lmscloud.de> > > =head1 COPYRIGHT > >diff --git a/koha-tmpl/intranet-tmpl/prog/en/includes/action-logs.inc b/koha-tmpl/intranet-tmpl/prog/en/includes/action-logs.inc >index 9df6b43226f..7b71a6d1db7 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/includes/action-logs.inc >+++ b/koha-tmpl/intranet-tmpl/prog/en/includes/action-logs.inc >@@ -1,5 +1,7 @@ > [% BLOCK translate_log_module %] > [% SWITCH module %] >+ [% CASE 'APIKEY' %] >+ <span>API keys</span> > [% CASE 'AUTH' %] > <span>Authentication</span>[% UNLESS Koha.Preference('AuthFailureLog') && Koha.Preference('AuthSuccessLog') %] > <i class="log-disabled fa-solid fa-triangle-exclamation" title="Log not enabled" data-log="AuthFailureLog|AuthSuccessLog"></i> >@@ -61,6 +63,8 @@ > <span>Return</span> > [% CASE 'CREATE' %] > <span>Create</span> >+ [% CASE 'GENERATE' %] >+ <span>Generate</span> > [% CASE 'CANCEL' %] > <span>Cancel</span> > [% CASE 'FILL' %] >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/viewlog.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/viewlog.tt >index 6e434a5c67f..28f0977e402 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/tools/viewlog.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/tools/viewlog.tt >@@ -123,7 +123,7 @@ > [% ELSE %] > <label for="moduleALL" class="viewlog"><input type="checkbox" id="moduleALL" name="modules" value="" /> All</label> > [% END %] >- [% FOREACH modx IN [ 'AUTH' 'CATALOGUING' 'AUTHORITIES' 'MEMBERS' 'ACQUISITIONS' 'SERIAL' 'HOLDS' 'ILL' 'CIRCULATION' 'CLAIMS' 'FINES' 'SYSTEMPREFERENCE' 'CRONJOBS', 'REPORTS', 'SEARCHENGINE', 'NOTICES', 'NEWS', 'RECALLS', 'SUGGESTION', 'TRANSFERS' ] %] >+ [% FOREACH modx IN [ 'APIKEY', 'AUTH' 'CATALOGUING' 'AUTHORITIES' 'MEMBERS' 'ACQUISITIONS' 'SERIAL' 'HOLDS' 'ILL' 'CIRCULATION' 'CLAIMS' 'FINES' 'SYSTEMPREFERENCE' 'CRONJOBS', 'REPORTS', 'SEARCHENGINE', 'NOTICES', 'NEWS', 'RECALLS', 'SUGGESTION', 'TRANSFERS' ] %] > [% IF modules.grep(modx).size %] > <label for="module[% modx | html %]" class="viewlog" > ><input type="checkbox" id="module[% modx | html %]" name="modules" value="[% modx | html %]" checked="checked" /> [% PROCESS translate_log_module module=modx %]</label >-- >2.52.0
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 37025
:
167397
|
167524
|
171014
|
185537
|
191344
| 191345