This section covers development and maintenance information pertinent to Xiden. This document will not try to repeat what the code says, but will instead offer broader context behind why things are the implemented the way they are. That is, the context that cannot be adequately summarized in code comments.
If you were looking for the API reference, see Xiden: API Reference. If you want a high-level overview of what Xiden is, see Xiden: A Guide for Functional Dependency Management in Racket.
To build all project deliverables, run make or make build. To run the tests, run make test. To do both, run make build test.
Instead of an install or uninstall command, Xiden expects a user to define transactions with the filesystem and request links (read: references) to the exact files they need. Some users might not appreciate an unconventional interface, so some push-back is expected.
Maintainers should refrain from adding aliases that conform to traditional package manager commands to Xiden, because they would not contribute functionality. They should instead suggest defining such aliases as shell scripts, which is a better medium for user preferences.
A more actionable complaint would address Xiden’s current requirement for Racket values by every flag, including boolean short flags (e.g. -U '#t'). This is a combination of parse-command-line’s interpretation of procedure arity and Xiden’s insistence on full ability to override the runtime configuration through several means.
Like any system that runs code from the Internet, Xiden can be used for nefarious purposes. This attack surface is made complicated due to differences in how Windows and Unix-like systems model permissions, and the flexibility of Xiden’s runtime configuration. Xiden offers security features to mitigate some risks, but administrators should configure their operating system to restrict the behavior of any user or group running a Xiden process. Failing to do so allows room for arbitrary code execution.
Each security-critical check is implemented using a composition of affirmations. An affirmation is a pure procedure that either returns a message, or the result of applying another procedure in tail position. The message says if an operation is consistent with the user’s affirmative consent, and names the affirmation used to create that message. Additionally, an affirmation procedure must have a cyclomatic complexity of at most 2.
For example, let’s look at a procedure that returns #t if a real number is an element of an exclusive interval.
If we define the computation with affirmations, the code becomes far more verbose.
(define-message $between (ok? stage)) (define (affirm-< n hi continue) (if (< n hi) (continue) ($between #f (object-name affirm-<)))) (define (affirm-> n lo continue) (if (> n lo) (continue) ($between #f (object-name affirm->)))) (define (num-between n lo hi) (affirm-> n lo (lambda () (affirm-< n hi (lambda () ($between #t (object-name num-between)))))))
Why do it this way? Because num-between returns an answer and the reason behind the answer in a single value. The original num-between would tell us if a number is not an element of (lo, hi), but the modified version tells us why it isn’t. If we see (object-name affirm-<), then we know that the number was too large for the interval without using < or keeping a reference to hi.
In the event an affirmation allows a dangerous operation, a program log will point to it. The goal is to offer transparent logs, reduced debugging time, and more accessible testing at the expense of more verbose code.