summaryrefslogtreecommitdiff
path: root/rt/docs/design_docs
diff options
context:
space:
mode:
Diffstat (limited to 'rt/docs/design_docs')
-rw-r--r--rt/docs/design_docs/acls228
-rw-r--r--rt/docs/design_docs/basic-definitions.txt54
-rw-r--r--rt/docs/design_docs/cli_spec361
-rw-r--r--rt/docs/design_docs/evil_plans9
-rw-r--r--rt/docs/design_docs/local_hacking32
5 files changed, 627 insertions, 57 deletions
diff --git a/rt/docs/design_docs/acls b/rt/docs/design_docs/acls
index bb093adcb..3b9d8567c 100644
--- a/rt/docs/design_docs/acls
+++ b/rt/docs/design_docs/acls
@@ -1,50 +1,206 @@
+$Header: /home/cvs/cvsroot/freeside/rt/docs/design_docs/acls,v 1.1 2002-08-12 06:17:07 ivan Exp $
-Does principal baz have right foo for object bar
-What rights does user baz have for object bar
+# {{{ Requirements
-# {{{ Which principals have right foo for object bar
+Here's the rough scheme I was thinking of for RT2 acls. Thoughts? I think
+it's a lot more flexible than RT 1.0, but not so crazily complex that
+it will be impossible to implement. One of the "interesting" features
+is the ability to grant acls based on watcher status. This now lives
+in design-docs/acls
+ jesse
-if ($args{'ObjectType'} eq 'Ticket') {
- $or_check_ticket_roles = " OR ( Groups.Domain = 'TicketRole' AND Groups.Instance = '".$args{'ObjectId'}."') ";
- # If we're looking at ticket rights, we also want to look at the associated queue rights.
- # this is a little bit hacky, but basically, now that we've done the ticket roles magic, we load the queue object
- # and ask all the rest of our questions about the queue.
- my $tick = RT::Ticket->new($RT::SystemUser);
- $tick->Load($args{'ObjectId'});
- $args{'ObjectType'} = 'Queue';
- $args{'ObjectId'} = $tick->QueueObj->Id();
+Who can rights be granted to:
-}
-if ($args{'ObjectType'} eq 'Queue') {
- $or_check_roles = " OR ( ( (Groups.Domain = 'QueueRole' AND Groups.Instance = '".$args{'ObjectId'}."') $or_check_ticket_roles )
- AND Groups.Type = ACL.PrincipalType AND Groups.Id = Principals.ObjectId AND Principals.PrincipalType = 'Group') ";
-}
+ users whose id is <foo>
+ users who are watchers of type <requestor/cc/admincc> for <queue/ticket> <id>
+ users who are watchers of type <requestor/cc/admincc> for <this ticket / this queue>
+
+
+what scope do these rights apply to
+ queue <id>
+ system
+
+
+What rights can be granted
+ Display Ticket
+ Manipulate Ticket
+ Only users with manipulate ticket level access will see comments
+ Maniplulate Ticket Status
+ Create Ticket
+
+ Admin Queue Watchers
+ Admin Ticket Watchers
+ Admin user accounts
+ Admin scrips
+ Admin scripscopes
+ Admin Queue ACLS
+ Admin System ACLs
+
+# }}}
+
+
+# {{{ Prinicpals These are the entities in your Access Control Element
+#
+
+Principal: What user does this right apply to
+
+ Made up of:
+ PrincipalScope, PrincipalType and PrincipalId
+
+
+ User:
+ Scope: User
+ Type: null
+ Id: A userid or 0
+
+ Owner:
+ Scope: Owner
+ Type: null
+ Id: none
+
+
+ Watchers:
+
+ Scope: Ticket
+ Type: Requestors; Cc; AdminCc
+ Id: A ticket id or 0 for "this ticket"
+
+ Scope: Queue
+ Type: Cc; AdminCc
+ Id: A queue id or 0 for "this queue"
+
+
+# }}}
+
+# {{{ Object: What object does this right apply to
+
+ Object is composed of an ObjectType and an ObjectId
+
+ Type: System
+ Id: NULL
+
+ Type: Queue
+ Id: Integer ref to queue id or 0 for all queues
+
+# }}}
+
+# {{{ Right: (What does this entry give the principal the right to do)
+
+
+
+ For the Object System:
+ System::SetACL
+ System::AdminScrips
-if (defined $args{'ObjectType'} ) {
- $or_look_at_object_rights = " OR (ACL.ObjectType = '".$args{'ObjectType'}."' AND ACL.ObjectId = '".$args{'ObjectId'}."') ";
+ User::Display
+ User::Create
+ User::Destroy
+ User::Modify
+ User::SetPassword
+
+
+ For the Object "Queue":
+ Queue::Admin
+ Queue::SetACL
+ Queue::Create
+ Queue::Display
+ Queue::Destroy
+ Queue::ModifyWatchers
+ Ticket::Create
+ Ticket::Destory
+ Ticket::Display
+ Ticket::Update
+ Ticket::UpdateRequestors
+ Ticket::UpdateCc
+ Ticket::UpdateAdminCc
+ Ticket::NotifyWatchers
+
+
+ DEFERRED
+
+ Ticket::SetStatus: (Values)
+ Open
+ Resolved
+ Stalled
+ <null> means any
+
+
+# }}}
+
+
+# {{{ Implementation:
+
+# {{{ SQL Schema
+CREATE TABLE ACL (
+ id int not null primary_key autoincrement,
+ PrinicpalId INT(11),
+ PrincipalType VARCHAR(16),
+ PrincipalScope VARCHAR(16),
+ ObjectType VARCHAR(16),
+ ObjectId INT,
+ Right VARCHAR(16)
+);
+
+# }}}
+
+# {{{ perl implementation of rights searches
+
+sub Principals {
+if (defined $Ticket) {
+ return "($UserPrincipal) OR ($OwnerPrincipal) OR ($WatchersPrincipal)";
+ }
+else {
+ return "($UserPrincipal) OR ($WatchersPrincipal)";
+ }
}
+
+$Principals = " ($UserPrincipal) OR ($OwnerPrincipal) OR ($WatchersPrincipal)";
+
+$UserPrincipal = " ( ACE.PrincipalScope = 'User') AND
+ ( ACE.PrincipalId = $User OR ACE.PrincipalId = 0)";
-my $query = "SELECT Users.* from ACL, Groups, Users, Principals, Principals UserPrinc, CachedGroupMembers WHERE
- Users.id = UserPrinc.ObjectId AND UserPrinc.PrincipalType = 'User' AND
- Principals.Id = CachedGroupMembers.GroupId AND
- CachedGroupMembers.MemberId = UserPrinc.ObjectId AND
- UserPrinc.PrincipalType = 'User' AND
- (ACL.RightName = 'SuperUser' OR ACL.RightName = '$right') AND
- (ACL.ObjectType = 'System' $or_look_at_object_rights) AND
- (
- (ACL.PrincipalId = Principals.Id AND
- Principals.ObjectId = Groups.Id AND
- ACL.PrincipalType = 'Group' AND
- (Groups.Domain = 'SystemInternal' OR Groups.Domain = 'UserDefined' OR Groups.Domain = 'ACLEquivalence')
- )
- $or_check_roles
- )";
+$OwnerPrincipal = " ( ACE.PrinciaplScope = 'Owner') AND
+ ( Tickets.Owner = "$User ) AND
+ ( Tickets.Id = $Ticket)";
+
+$WatchersPrincipal = " ( ACE.PrincipalScope = Watchers.Scope ) AND
+ ( ACE.PrincipalType = Watchers.Type ) AND
+ ( ACL.PrincipalId = Watchers.Value ) AND
+ ( Watchers.Owner = $User )";
+
+$QueueObject = "( ACE.ObjectType = 'Queue' and (ACE.ObjectId = $Queue OR ACE.ObjectId = 0)";
+
+$SystemObject = "( ACE.ObjectType = 'System' )";
+
+
+# This select statement would figure out if A user has $Right at the queue level
+
+SELECT ACE.id from ACE, Watchers, Tickets WHERE (
+ $QueueObject
+ AND ( ACE.Right = $Right)
+ AND ($Principals))
+
+# This select statement would figure outif a user has $Right for the "System"
+
+SELECT ACE.id from ACE, Watchers, Tickets WHERE (
+ ($SystemObject) AND ( ACE.Right = $Right ) AND ($Principals))
# }}}
-What objects does principal baz have right foo for
-;
+# }}}
+
+# {{{ Examples
+#
+
+# }}}
+
+
+
+Unaddressed issues:
+
+ There needs to be a more refined method for grouping users, such that members of the customer service department
+can't change sysadmins' passwords.
diff --git a/rt/docs/design_docs/basic-definitions.txt b/rt/docs/design_docs/basic-definitions.txt
new file mode 100644
index 000000000..23d2c5748
--- /dev/null
+++ b/rt/docs/design_docs/basic-definitions.txt
@@ -0,0 +1,54 @@
+(todo ... basically, those are untouched from 1.0)
+Ticket
+Queue
+(...more?)
+
+Requestor
+
+ (...definition of a requestor .. blahblah)
+
+ I'm often doing a distinction between "Internal Requestors" and "External
+ Requestors" (see below). The system doesn't make any difference between
+ requestors, but the distinction might be useful to discuss usage patterns,
+ templates and configurations.
+
+
+External Requestor
+
+ Might be a customer or a potential customer. The External Requestor
+ should be treated as a VIP. (S)he shouldn't need to see too much of RT.
+ The support (s)he gets should be as personal as possible. The external
+ requestor might eventually get access to the Web UI, but only to track
+ her/his own requests. If you're not planning to use RT for handling
+ external customers, all your requestors are probably "Internal
+ Requestors".
+
+
+Watcher
+
+ Somebody that are "subscribing" to a queue or a ticket (or something
+ differently). Basicly, somebody watching a queue or a ticket should get
+ all updates by email. A requestor is a (special) watcher.
+
+
+Regular Watcher
+
+ People within the same organization, people that have read access to whole
+ queues.
+
+ I consider "Regular Watchers" as well as "Internal Requestors" as more
+ robust and capable human beeings than the fragile customers. We don't
+ mind letting them get entagled with RT, and we let them access the Web UI.
+ They can live with beeing just the Cc or Bcc at an email.
+
+
+Internal Requestor
+
+ An Internal Requestor is usually internal to the company. He might be 1st
+ line support sending matters to tech support or similar. Might be an
+ internal employee sending matters to tech support (or even 1st line
+ support if he's not sure where to send matters). It might also be that
+ "ordinary" requestors actually might be treated as intelligent human
+ beeings rather than VIPs, i.e. in open source projects ... we'll still
+ call them "Internal Requestors" as they don't need the special VIP
+ treatment.
diff --git a/rt/docs/design_docs/cli_spec b/rt/docs/design_docs/cli_spec
index ae5f29f76..48a7f34e1 100644
--- a/rt/docs/design_docs/cli_spec
+++ b/rt/docs/design_docs/cli_spec
@@ -1,31 +1,354 @@
-Things the cli must do
- create ticket
- comment
- reply
- update ticket metadata
- search for tickets
- update a bunch of tickets.
- list tickets
- login/logout
+Find tickets to operate on:
+ --id=<tickets> Find only tickets in the range <tickets>
+ synonyms:
+ --limit-id, --tickets, --limit-tickets
+ --limit-queue=<queue>
+ --limit-status=<status>
+ --limit-owner=<owner>
+ --limit-priority=<priority>
+ --limit-requestor=<email>
+ --limit-subject=<string> (Subject contains)
+ --limit-body=<string> (body contains)
+ --limit-created=(before/after) <date>
+ --limit-due=(before/after) <date>
+ --limit-starts=(before/after) <date>
+ --limit-started=(before/after) <date>
+ --limit-first=<int> Start on the <int>th row returned by the
+ database
+ --limit-rows=<int> Find only <int> rows
-should support multiple rt servers
+Display:
+ --show shows a ticket history
+ --history ditto
-create/edit/update should use EDITOR or take from a file or stdin
+ --summary default option. shows a ticket summary
+ --format Optional format string. If not specified,
+ uses the value of ENV{'RT_LISTING_FORMAT'}
+ or an internal default
+
-should be able to update ticket sttributes from a commandline without invoking an editor or needing to use stdin.
+Basic ticket editing:
-login/logout should store RT session cookies rather than constantly transmitting the username/password combo.
+ --status=(open|stall|resolve|kill)
+ --subject=<string>
+ --owner=<owner>
+ --queue=<queue>
+ --time-left=<minutes>
-rtserver and rt username should come from env variables. but should be able to be overridden by commandline options.
+Watcher-related editing:
-rt password should be able to be specified on the commandline (say from a script) or, failing that be prompted for within the application (as rt's sbin/initdb script does) ...or maybe able to be read from a stash file on disk.
+ --add-requestor=<email>
+ --del-requestor=<email>
+ --add-cc=<email>
+ --del-cc=<email>
+ --add-admincc=<email>
+ --del-admincc=<email>
-must be able to dowaload attachments from cli.
-
- it might also be cool to be able to generate session-length urls for attavhments so you can use a browser. but that's not necessary.
+Priority related editing:
+ --priority=<int>
+ --final-priority=<int>
-I'm envisioning this as similar to the subversion cli, actually.
+Date related editing:
+
+ --due=date
+ --starts=date
+ --started=date
+ --contacted=date
+
+
+
+Ticket updates:
+
+ --comment
+ --reply | --respond
+
+
+Links
+
+ --add-link
+ --type=<DependsOn|MemberOf|RelatedTo>
+ needs one of:
+ --target=<ticketid>
+ --base=<ticketid>
+
+ --del-link <link-id>
+
+
+
+Condiments:
+ any update can take:
+
+ --time-taken <minutes>
+
+ Ticket updates can take:
+
+ --source -- specify a source file to read the content from
+ --edit = give me an editor to edit the message
+ --no-edit = don't give me an editor to edit the message.
+
+
+
+
+----- Forwarded message from deborah kaplan <deborah@curl.com> -----
+
+Date: Fri, 14 Apr 2000 11:43:18 -0400 (EDT)
+From: deborah kaplan <deborah@curl.com>
+To: Jesse <jesse@fsck.com>
+Subject: Re: [rt-devel] RT Projects list
+
+Finally, here is the functional spec for the command line
+interface. This is for the user interface only; if you think
+this is right, I will add the administrative interface as well.
+Should I post to rt-devel, add to the ticket, or just modify
+based on your kibbitzing? When you are happy with it I'll start
+the code.
+
+-deborah
+
+
+RT command line interface functional specification
+Author: Deborah Kaplan (Deborah@suberic.net)
+Version:0.1
+
+Requirements:
+
+RT needs a CLI for various reasons. If a user is restricted to a
+dumb terminal, she needs to be able to access the RT database and
+manipulate it fully. The full functionality of both the RT
+database and the RT administrative interface should be available
+from this CLI.
+
+There are two possible types of CLI which I will discuss here.
+The first is a curses-style interface, which allows the user to
+move about a series of menus and choices, usually using arrow
+keys. As RT supplies a Web interface, there is no need for this
+curses-style interface to be written as part of RT. Instead, the
+RT developers should pick one tty-based Web browser (e.g. lynx,
+w3m) and make sure that all of the RT pages are easily readable
+with that tty based browser. Installation of that browser should
+be recommended in the RT installation documentation as a
+supported method of accessing RT from a tty.
+
+The second possible type of CLI is more minimal: a series of
+commands which can be run at a UNIX command prompt which provide
+full functionality to the RT database and administrative
+interface. There are two major benefits to this second type of
+CLI. First of all, in order to use this CLI, you need no extra
+tools (Web browsers, etc.). All that is required is a UNIX
+command line prompt and an installation of RT. Secondly, a user
+of RT who has a very specific command to run and who knows the
+appropriate CLI commands can accomplish her task much more
+quickly with a single command then she could navigating through a
+menu based interface.
+
+In the specification, I will describe the second type of CLI.
+
+Caveats:
+
+This specification draws heavily on the structure of formatting
+command line options for cvs. RT faces a smaller version of the
+same kinds of problems cvs faces: we want to create a very rich
+command set without sacrificing ease-of-use.
+
+I am not wedded to any specific command names if they seem
+impractical; I merely am proposing the command names that seem
+reasonable to me at this moment.
+
+Finally, I am finding the functioning of the web UI from RT 1.
+If the functionality differs greatly in RT 2, I will need to
+modify this specification.
+
+Specification:
+
+There are two commands: "rt", which is the primary interface to
+the database, and "rtadmin", which is the administrative
+interface to the database.
+
+The format of an rt command is as follows:
+
+ rt <command>
+ <command> is one of:
+
+ - help
+ print an overview of the commands which can be run
+
+ - print <queue> <options>
+ with no options, dump to the screen a list of all open
+ requests in <queue> -- the equivalent of "Display Queue" in
+ the existing Web interface.
+
+ <queue> is the name of an RT queue
+ <option> is either:
+
+ -f <filename> | --filename <filename>
+ where <filename> is the name of a file (defaulting to
+ ~/.rtrc) in which the options described below can be
+ placed in the format "^ <long option name> <option value>
+ $".
+
+ Or a series of the following options:
+
+ -o <owner name> | --owner <owner name>: restrict tickets
+ viewed to those owned by <owner name>.
+ This option can be used multiple times in one call of
+ the rt command in order to produce a list which
+ contains tickets owned by multiple owners. Giving the
+ empty string ("") as an option to this switch will
+ restrict tickets viewed to those which have no owner.
+ If this switch is given with no argument, the option
+ defaults to the user name of the currently running
+ process.
+
+ -r <requestor name> | --requestor <requestor name>:
+ restrict tickets viewed to those requested by <requestor
+ name>.
+ This option can be used multiple times in one call of
+ the rt command in order to produce a list which
+ contains tickets requested by multiple requesters. If
+ this switch is given with no arguments, it produces an
+ error.
+
+ -s <status> | --status <status>: restrict tickets viewed
+ to those with the status named in <status>.
+ This option can be used multiple times in one call of
+ the rt command in order to produce a list which
+ contains tickets with multiple statuses (statii?
+ Dragon NaturallySpeaking recognizes "statuses" as a
+ word). This option defaults to status "open".
+
+ -j <subject> | --subject <subject>: restrict tickets
+ viewed to those which contain <subject> as a substring in
+ the subject field of the ticket.
+ This command can be used multiple times in one call of
+ the rt command in order to produce a list which
+ contains tickets with various subject substrings. If
+ the option is called with no argument, the result is
+ an error.
+
+ -h | --help: print a usage message.
+
+ -n | --number: print out a specific ticket.
+ This command can be used multiple times to produce a
+ list which contains multiple tickets. If the option
+ is called with no argument, the result is an error.
+
+ This completes all of the print options which are available
+ in the Web interface, except the sort options. I maintain
+ that this command is already excessively complex, and that
+ adding functionality which can be replicated easily by
+ standard UNIX tools is unnecessary added complexity. I
+ recommend that the man pages and documentation for this
+ option contain an example of a command line run (e.g. of rt |
+ awk) which replicates the sorting functionality provided by
+ the Web interface.
+
+ - edit <ticket> <options>
+ with no options, or with no <ticket>, produces the same
+ output as the --help option.
+ Otherwise, edits the ticket with number <ticket> as
+ indicated in the options given. All options listed below
+ except for --help and --number can be used in conjunction
+ with one another to change many features of the same ticket
+ all at once.
+
+ -h | --help: print usage message
+
+ -s <status> | --status <status>: change the status to the
+ status listed in <status>.
+ No <status> listed, or 1 listed it does not come from
+ a list of approve statuses, produces an error.
+
+ -o <owner name> | --owner <owner name>: set to the owner
+ of the ticket the owner named.
+ Follows whatever convention is finally decided on for
+ the requirement to steal a ticket that is owned by
+ somebody else. No <owner named> listed has the user
+ who is running the rt program take the ticket. If
+ that user is not a valid owner, or the 1 listed does
+ not come from a list of approve names, produces an
+ error.
+
+ -r <requestor name> | --requestor <requestor name>: sets
+ the requestor to <requestor name>.
+ Follows any conventions that the Web UI follows to
+ make sure that this is a legal name. If not legal, or
+ left blank, produces an error.
+
+ -j <subject> | --subject <subject>: sets the subject of
+ the ticket to <subject>.
+ If the option is called with no argument, the result
+ is an error.
+
+ -n <number one> <number 2> | --number <number one>
+ <number 2>: merges ticket number <number one> into ticket
+ <number 2>.
+ If both arguments are not provided, the result is an
+ error.
+
+ -q <queue> | --queue <queue>: set the queue to that
+ named.
+ If <queue> is not listed, or the 1 listed does not
+ come from a list of approve queues, produces an
+ error.
+
+ -a <area> | --area <area>: set the area of the ticket to
+ that named.
+ If <area> is not listed, or the 1 listed does not come
+ from a list of approve areas, produces an error.
+
+ -c <time stamp> | --contact <time stamp>: sets the last
+ user contact field, and produces an error if the format
+ is invalid.
+ If the argument is left blank, sets the last user
+ contact field to now.
+
+ -p <priority> | --priority <priority>: sets the current
+ priority to the 1 listed.
+ Produces an error if the argument is left blank.
+
+ -f <priority> | --final <priority>: sets the final
+ priority to the 1 listed.
+ Produces an error if the arguments left blank.
+
+ -d <date due> | --datedue <date due>: sets the due date
+ to the 1 listed.
+ Produces an error if the argument is left blank, or if
+ the format is invalid.
+
+ - comment <options>
+ with no options, this command reads from standard input
+ until it sees EOF and appends that to the ticket as a
+ comment.
+
+ -h | --help: print usage message
+
+ -c | --comment: append as a comment. This is the default behavior.
+
+ -r | --reply: append as a reply.
+
+ -f <filename> | --file <filename>: can be used with
+ either the comment or reply options. Instead of reading
+ from standard input, read the text of the comment or
+ reply from the file <filename>.
+
+ - report <options>
+ this command is a place holder for reporting functionality
+ which does not yet exist. It will probably have the
+ default behavior to select reports at the command line or
+ choose default reports from a .rtrc file. In a future
+ version, it can output graphs in some graphical format.
+
+
+
+----- End forwarded message -----
+
+--
+jesse reed vincent -- root@eruditorum.org -- jesse@fsck.com
+70EBAC90: 2A07 FC22 7DB4 42C1 9D71 0108 41A3 3FB3 70EB AC90
+
+"If IBM _wanted_ to make clones, we could make them cheaper and faster than
+anyone else!" - An IBM Rep. visiting Vassar College's Comp Sci Department.
diff --git a/rt/docs/design_docs/evil_plans b/rt/docs/design_docs/evil_plans
index 5b5cc58c1..34b9f81a2 100644
--- a/rt/docs/design_docs/evil_plans
+++ b/rt/docs/design_docs/evil_plans
@@ -3,7 +3,8 @@ Current planned 2.2 feature list. subject to change.
Core
-
+Should Make "Owner" a watcher type, rather than a special ticket attribute,
+ under the hood. This wins for ACL and code consistency reasons.
Web UI
@@ -66,6 +67,8 @@ nice Scrips could apply to a list of queues, rather than just one queue or
Custom fields
+Must "KeywordSelects" become "Custom Fields"
+Should String and multi-string custom fields.
Nice Date custom fields
Nice Some way to order and group custom fields.
Nice Default values
@@ -76,6 +79,8 @@ Nice Make custom fields apply to an enumerated list of queues,
Web infrastructure
+Must Full fastcgi support.
+
Installation
@@ -111,7 +116,7 @@ Nice Export full ticket metadata and history as XML
Note: I currently favor the REST philosophy that GET and POST to specific,
defined URLs provides everything one needs to build comprehensive
web services without the massive added complexity of a SOAP or XML-RPC
- framework. Sadly, the world doesn't agree with me
+ framework.
ACLs:
diff --git a/rt/docs/design_docs/local_hacking b/rt/docs/design_docs/local_hacking
new file mode 100644
index 000000000..c06d1126d
--- /dev/null
+++ b/rt/docs/design_docs/local_hacking
@@ -0,0 +1,32 @@
+To facilitate local hacking, RT needs a mechanism to allow site administrators
+to easily add HTML templates for the web ui and to replace sections
+of code in RT's core modules _without_ having to modify those modules
+
+We'll use several methods to achieve this goal.
+
+ Webui
+ HTML::Mason allows users to create multiple
+component hierarchies. RT should ship with a local component root
+defined and available. This root should be configured as the "primary"
+component root.
+
+
+ Core modules
+
+ This gets a bit trickier. we want to allow people to trivially
+subclass core modules and to use those subclasses throughout the code.
+
+The way we're going to handle this is by setting up a number of subroutines
+in config.pm that look something like this:
+
+sub NewTicketObj {
+ eval "require $TicketClass";
+ my $object = new $TicketClass;
+ return ($object);
+}
+
+# This variable is used for ref type checking
+$TicketClass = "RT::Ticket";
+
+we could use an eval around the require and thus completely avoid specifying
+the object in two places. which feels like a win. but i'm worried about perf.