• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

daycry / jwt / 27087995322

06 Jun 2026 08:38PM UTC coverage: 89.775% (+1.1%) from 88.718%
27087995322

push

github

daycry
chore(psalm): baseline framework-helper false positives in ApiCustomisersTest

config() (CI4 helper) and the setUp() MissingOverrideAttribute are already
baselined for the other test files; add the new test file's equivalent entries
so `composer qa` (psalm) is green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

439 of 489 relevant lines covered (89.78%)

16.16 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.63
/src/Commands/JWTGenerateKey.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace Daycry\JWT\Commands;
6

7
use CodeIgniter\CLI\BaseCommand;
8
use CodeIgniter\CLI\CLI;
9
use Exception;
10

11
class JWTGenerateKey extends BaseCommand
12
{
13
    protected $group       = 'JWT';
14
    protected $name        = 'jwt:key';
15
    protected $description = 'Generate a secure JWT signing key';
16
    protected $usage       = 'jwt:key [length]';
17
    protected $arguments   = [
18
        'length' => 'Key length in bytes (default: 32)',
19
    ];
20
    protected $options = [
21
        '--show'  => 'Display the key instead of updating .env file',
22
        '--force' => 'Force overwrite existing key in .env',
23
    ];
24

25
    public function run(array $params): int
26
    {
27
        $length = (int) ($params[0] ?? 32);
10✔
28

29
        // Validate length. 32 bytes (256-bit) is the floor for HS256, the default
30
        // signer; a shorter secret would otherwise fail only later, at encode().
31
        if ($length < 32) {
10✔
32
            CLI::error('Key length must be at least 32 bytes (256-bit) to safely sign with HS256.');
1✔
33

34
            return EXIT_USER_INPUT;
1✔
35
        }
36

37
        if ($length > 128) {
9✔
38
            CLI::error('Key length cannot exceed 128 bytes');
1✔
39

40
            return EXIT_USER_INPUT;
1✔
41
        }
42

43
        try {
44
            // Generate secure random key
45
            $key = base64_encode(random_bytes($length));
8✔
46

47
            if (CLI::getOption('show')) {
8✔
48
                $this->displayKey($key, $length);
3✔
49

50
                return EXIT_SUCCESS;
3✔
51
            }
52

53
            return $this->updateEnvFile($key);
5✔
54
        } catch (Exception $e) {
×
55
            CLI::error('Failed to generate key: ' . $e->getMessage());
×
56

57
            return EXIT_ERROR;
×
58
        }
59
    }
60

61
    private function displayKey(string $key, int $length): void
62
    {
63
        CLI::write('Generated JWT Key (' . $length . ' bytes):', 'yellow');
3✔
64
        CLI::write($key, 'green');
3✔
65
        CLI::newLine();
3✔
66
        CLI::write('Add this to your .env file:', 'yellow');
3✔
67
        CLI::write("jwt.signer={$key}", 'cyan');
3✔
68
        CLI::newLine();
3✔
69
        CLI::write('⚠️  Keep this key secure and never commit it to version control!', 'red');
3✔
70
    }
71

72
    /**
73
     * Resolve the .env file path. Override in tests to redirect to a sandbox.
74
     */
75
    protected function envPath(): string
76
    {
77
        return ROOTPATH . '.env';
×
78
    }
79

80
    /**
81
     * Resolve the .env.example file path. Override in tests.
82
     */
83
    protected function envExamplePath(): string
84
    {
85
        return ROOTPATH . '.env.example';
×
86
    }
87

88
    private function updateEnvFile(string $key): int
89
    {
90
        $envPath        = $this->envPath();
5✔
91
        $envExamplePath = $this->envExamplePath();
5✔
92

93
        // Check if .env exists
94
        if (! file_exists($envPath)) {
5✔
95
            CLI::error('.env file not found. Please create one first.');
2✔
96
            CLI::write('You can copy from .env.example if it exists:', 'yellow');
2✔
97
            if (file_exists($envExamplePath)) {
2✔
98
                CLI::write("cp {$envExamplePath} {$envPath}", 'cyan');
1✔
99
            }
100

101
            return EXIT_ERROR;
2✔
102
        }
103

104
        $envContent = file_get_contents($envPath);
3✔
105

106
        // Check if jwt.signer already exists
107
        if (preg_match('/^jwt\.signer\s*=.*$/m', $envContent)) {
3✔
108
            // In testing environment or with --force flag, skip prompt
109
            $isTestingEnv   = (getenv('CI_ENVIRONMENT') === 'testing' || getenv('APP_ENV') === 'testing');
2✔
110
            $forceOverwrite = CLI::getOption('force') || $isTestingEnv;
2✔
111

112
            if (! $forceOverwrite && CLI::prompt('JWT key already exists in .env. Overwrite?', ['y', 'n']) === 'n') {
2✔
113
                CLI::write('Operation cancelled.', 'yellow');
×
114

115
                return EXIT_USER_INPUT;
×
116
            }
117

118
            // Update existing key
119
            $envContent = preg_replace('/^jwt\.signer\s*=.*$/m', "jwt.signer={$key}", $envContent);
2✔
120
        } else {
121
            // Add new key
122
            $envContent .= "\n# JWT Configuration\njwt.signer={$key}\n";
1✔
123
        }
124

125
        if (file_put_contents($envPath, $envContent)) {
3✔
126
            CLI::write('✅ JWT key successfully added to .env file', 'green');
3✔
127
            CLI::write('Generated key: ' . $key, 'cyan');
3✔
128
            CLI::newLine();
3✔
129
            CLI::write('⚠️  Keep your .env file secure and never commit it to version control!', 'red');
3✔
130

131
            return EXIT_SUCCESS;
3✔
132
        }
133

134
        CLI::error('Failed to write to .env file. Check permissions.');
×
135

136
        return EXIT_ERROR;
×
137
    }
138
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc