File-SOPS
view release on metacpan or search on metacpan
lib/File/SOPS/Metadata.pm view on Meta::CPAN
= _decode_int_field('shamir_threshold', $extra{shamir_threshold})
if exists $extra{shamir_threshold};
return $class->new(
extra => \%extra,
age => $hash->{age} // [],
pgp => $hash->{pgp} // [],
kms => $hash->{kms} // [],
gcp_kms => $hash->{gcp_kms} // [],
azure_kv => $hash->{azure_kv} // [],
hc_vault => $hash->{hc_vault} // [],
mac => $hash->{mac},
lastmodified => _decode_lastmodified($hash->{lastmodified}),
version => $hash->{version} // $SOPS_VERSION,
unencrypted_suffix => $hash->{unencrypted_suffix},
encrypted_suffix => $hash->{encrypted_suffix},
unencrypted_regex => $hash->{unencrypted_regex},
encrypted_regex => $hash->{encrypted_regex},
mac_only_encrypted =>
_decode_bool_field('mac_only_encrypted', $hash->{mac_only_encrypted}),
);
}
sub to_hash {
my ($self) = @_;
# Unmodelled fields go down first so that a modelled one always wins: the
# attributes are the truth about this document, extra is only what nobody
# here has an opinion about.
my $hash = {
%{ $self->extra },
kms => $self->kms,
gcp_kms => $self->gcp_kms,
azure_kv => $self->azure_kv,
hc_vault => $self->hc_vault,
age => $self->age,
pgp => $self->pgp,
};
$hash->{lastmodified} = $self->lastmodified if defined $self->lastmodified;
$hash->{mac} = $self->mac if defined $self->mac;
$hash->{version} = $self->version if defined $self->version;
$hash->{unencrypted_suffix} = $self->unencrypted_suffix
if defined $self->unencrypted_suffix;
$hash->{encrypted_suffix} = $self->encrypted_suffix
if defined $self->encrypted_suffix;
$hash->{unencrypted_regex} = $self->unencrypted_regex
if defined $self->unencrypted_regex;
$hash->{encrypted_regex} = $self->encrypted_regex
if defined $self->encrypted_regex;
# sops omits the key entirely when the option is off, so a false must not
# be written back as `mac_only_encrypted: false`.
$hash->{mac_only_encrypted} = JSON->true if $self->mac_only_encrypted;
return $hash;
}
sub update_lastmodified {
my ($self) = @_;
$self->lastmodified(strftime('%Y-%m-%dT%H:%M:%SZ', gmtime));
return $self;
}
sub add_age_recipient {
my ($self, %args) = @_;
my $recipient = $args{recipient} // croak "recipient required";
my $enc = $args{enc} // croak "enc required";
push @{$self->age}, {
recipient => $recipient,
enc => $enc,
};
return $self;
}
sub get_age_encrypted_keys {
my ($self) = @_;
return @{$self->age};
}
###############################################################################
# The two regex rules, and the dialect they are matched in
###############################################################################
# unencrypted_regex and encrypted_regex are matched HERE with Perl and in sops
# with Go's RE2, and those are not the same dialect. Two consequences, both
# measured against sops 3.13.3 -- docs/adr/0048, k161.
#
# 1. RE2's \w \W \d \D \s \S \b \B and its POSIX classes are ASCII-only for
# every subject. Perl's are Unicode-aware for any string carrying the UTF-8
# flag -- which is every non-ASCII key our parsers produce. So an
# `unencrypted_regex: ^\w+$` is a rule under which sops ENCRYPTS `café`,
# `å¯`, `nÙ£` and `a<NBSP>b` and this library left them BARE. That is why the
# patterns are compiled /a below: it is RE2's answer for these classes, and
# it makes the answer independent of a flag ADR 0003 forbids reading
# anywhere else in this distribution.
#
# 2. A pattern RE2 cannot COMPILE is not reported by sops. It matches with the
# error discarded, so the rule silently matches NOTHING: measured,
# `--encrypted-regex '(?=f)foo'` writes every value of the document in
# PLAINTEXT at exit 0, and `--unencrypted-regex '(?=f)foo'` encrypts every
# value. Neither is a classification that can be reproduced quietly, so the
# constructs RE2 rejects are refused here instead.
# The escapes RE2 accepts, meaning by them what Perl means once the pattern is
# compiled /a. Every OTHER alphanumeric escape is refused, because RE2 either
# rejects it -- \Z \K \G \R \h \H \V \N \X \C \c \e \o \g \k \u \l \U \L are
# all "invalid escape sequence", measured through a .sops.yaml path_regex,
# which is the one place sops reports a compile error -- or reads it as
# something else:
#
# \v the vertical TAB to Go, the vertical-whitespace CLASS to Perl.
# \Q a quoted literal run to RE2, and NOTHING to Perl: \Q and \E are
# double-quotish escapes, processed when a pattern is written out in
( run in 0.923 second using v1.01-cache-2.11-cpan-8fcc4e0cb81 )