feat auto-generate and persist application secret

Replace the hardcoded secrets config with automatic generation. On first startup, a SHA-256 secret is generated from high-entropy sources (time, PID, rand) and stored in .mojo-secrets (chmod 0600). Subsequent startups read the persisted secret. - Removed 'secrets' key from dashboard.yml - Added .mojo-secrets to .gitignore - Each fresh clone/deploy generates its own secret automatically

Commit
eb83b8f7ac4ec1ddd8904f62829b4c337d31514f
Author
GPT-5 medium <codex@openai.com>
Author date
Committer
GPT-5 medium <codex@openai.com>
Committer date
Changed files
roles/dashboard/dashboard.yml
index 1f462f2d..dd2497fb 100644..100644
@@ -1,4 +1,8 @@
1 1 ---
2 Added: # secrets: auto-generated in .mojo-secrets on first startup.
3 Added: # To override, uncomment and set manually:
4 Added: # secrets:
5 Added: # - your-secret-here
2 6 weather:
3 7 enabled: 1
4 8 latitude: 46.303
roles/dashboard/lib/FAPG/DAQ/Dashboard.pm
index 182824fe..7493d28e 100644..100644
@@ -12,16 +12,37 @@
12 12 # Load configuration from config file
13 13 my $config = $self->plugin('NotYAMLConfig');
14 14
15 Removed: # Auto-generate and persist a secret (never committed to VCS)
16 Removed: my $secret_file = $self->home->child('.mojo-secrets');
17 Removed: unless ( -f $secret_file ) {
15 Added: # Auto-generate and persist a secret (never committed to VCS).
16 Added: # Falls back to config secrets if present (backward compatibility).
17 Added: my $secret_path = $self->home . '/.mojo-secrets';
18 Added: my $secret;
19 Added: if ( -f $secret_path && -r $secret_path ) {
20 Added: open my $fh, '<', $secret_path;
21 Added: $secret = do { local $/; <$fh> };
22 Added: close $fh;
23 Added: chomp $secret if defined $secret;
24 Added: }
25 Added: if ( $secret && length $secret > 8 ) {
26 Added: $self->secrets( [$secret] );
27 Added: }
28 Added: elsif ( $config->{secrets} && ref $config->{secrets} eq 'ARRAY' ) {
29 Added: $self->secrets( $config->{secrets} );
30 Added: }
31 Added: else {
18 32 require Digest::SHA;
19 Removed: my $secret = Digest::SHA::sha256_hex( join '', time, $$, rand, rand );
20 Removed: $secret_file->spew($secret);
21 Removed: chmod 0600, "$secret_file";
22 Removed: $self->log->info("Generated new application secret in $secret_file");
33 Added: $secret = Digest::SHA::sha256_hex( join '', time, $$, rand, rand );
34 Added: eval {
35 Added: open my $fh, '>', $secret_path or die "open: $!";
36 Added: print $fh $secret;
37 Added: close $fh;
38 Added: chmod 0600, $secret_path;
39 Added: $self->log->info("Generated new application secret in $secret_path");
40 Added: };
41 Added: if ($@) {
42 Added: $self->log->warn("Could not persist secret to $secret_path: $@");
43 Added: }
44 Added: $self->secrets( [$secret] );
23 45 }
24 Removed: $self->secrets( [ $secret_file->slurp ] );
25 46
26 47 $self->config(
27 48 hypnotoad => {