ENOSUCHBLOG

Programming, philosophy, pedaling.


KBSecret 0.6.x: Sensitive Fields, Error Handling, and DRYer Sessions

Jul 5, 2017     Tags: devblog, kbsecret, programming, ruby    

This post is at least a year old.

Previously.

The KBSecret 0.6.x line has officially begun! 0.6.0 was released on 7/1, followed by 0.6.1 on 7/4 and 0.6.2 today (7/5).

These updates bring a few substantial improvements…

Sensitive Fields

The fields within KBSecret record types can now be marked as either “sensitive” (the default) or “non-sensitive.” This provides a much-needed hint to commands like kbsecret new, which used to be overly conservative during user input, echoing nothing back to the user:

1
2
3
4
5
6
7
8
9
# old
$ kbsecret new login top-secret-website
Username?           # not echoed!
Password?           # not echoed!

# new
$ kbsecret new login top-secret-website
Username? bob       # correctly echoed!
Password?           # not echoed, since passwords are sensitive!

Of course, this works for non-login types as well:

1
2
3
4
5
6
7
$ kbsecret new env top-secret-api
Variable? TOP_SECRET_API   # correctly echoed!
Value?                     # not echoed, since environment values are sensitive!

$ kbsecret new snippet not-so-secret
Code? curl example.com     # correctly echoed!
Description? fetches site  # correctly echoed!

The actual library change for this functionality is relatively minor, as can be seen in the KBSecret::Record::Login class.

The old data definition:

1
2
3
4
class Login < Abstract
  data_field :username
  data_field :password
end

And the new:

1
2
3
4
class Login < Abstract
  data_field :username, sensitive: false
  data_field :password
end

Can you spot the difference? 😉

Error Handling

0.5.x brought some nice error handling in the form of the messages produced by Dreck.parse, but 0.6.x takes it to the next level in terms of coverage and consistency:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# correct arity/argument length checking
$ kbsecret new
Fatal: Too few arguments given (0, expected >=2).

# correct reporting of unknown flags
$ kbsecret list --quux
Fatal: Unknown option '--quux'.

# ensuring a session exists
$ kbsecret list --session quux
Fatal: Unknown session: 'quux'.

# in the rare event of corrupted/bad session data (more on this below)
$ kbsecret env --show-all
Fatal: Failed to load record in file: top-secret-api.json.

The best part: all of the above errors are generated and propagated programmatically, with no ugly die if or abort if logic! 1

This is done by identifying as many potential exceptions as possible during the option and argument parsing phase, and then propagating them as exceptions. From KBSecret::CLI:

1
2
3
4
5
6
7
8
9
10
def initialize(&block)
  @trailing = ARGV
  guard { instance_eval(&block) }
end

def guard
  yield
rescue => e
  die "#{e.to_s.capitalize}."
end

DRYer Sessions

0.5.6 included ensure_session! as a way to catch incorrect (i.e., nonexistent) sessions during the option and argument parsing phase.

0.6.x expands this to produce CLI#session, eliminating the need to call Session.new label: :foo explicitly in nearly all circumstances.

The old style:

1
2
session = Session.new label: cmd.opts[:session] # the value of --session
label   = session[label]

…and the new style:

1
label = cmd.session[label]

As mentioned above, this allows us to catch an entire class of session errors (corrupted data, etc) far earlier.

When it does become necessary to instantiate a KBSecret::Session explicitly, we can use CLI#guard to take care of any potential exceptions.

Old:

1
Session.new label: :whatever # user might see exceptions!

New:

1
cmd.guard { Session.new label: :whatever } # user sees error messages!

…and some other stuff

In 0.5.x, every non-builtin kbsecret command was guaranteed to take two flags: --help for a simple help message, and --introspect-flags for a dump of flags and subcommands recognized by the command.

In 0.6.x, I added two more universal flags: --verbose (-V) and --no-warn (-w). These can be used to enable and suppress verbose and warning messages, respectively, on the standard error stream. CLI#info and CLI#warn are the corresponding methods.

Since four universal flags is a bit much to document individually for each individual kbsecret command, I moved their documentation to only kbsecret(1) under “UNIVERSAL COMMAND OPTIONS”.

Documentation-wise, I fixed a weird formatting error in the YARD documentation by deleting some superfluous comments and reported the bug upstream.

Stay tuned for KBSecret 0.7.x!

- William


  1. There are a few places left where errors are propagated manually, but none of these examples are cases of those.