p4_protect.py #2

  • //
  • guest/
  • sam_stafford/
  • scripts/
  • p4_protect.py
  • View
  • Commits
  • Open Download .zip Download (4 KB)
import argparse
import shlex
import sys

import P4

from typing import Dict, List, Optional, Set

# Build up dict of specified permission level to granted permissions.
perms = {}  # type: Dict[str, Set[str]]

# Start with all the atomic =levels.
for perm in ['list', 'read', 'branch', 'open', 'write', 
             'review', 'owner', 'admin', 'super']:
  perms['=' + perm] = set([perm])

# All of the rest are built of other levels.
# Disclaimer: not actually sure these are right because the doc is
# a bit vague and I don't have the server source in front of me.

perms['list'] = perms['=list']
perms['read'] = perms['list'] | perms['=branch'] | perms['=read']
perms['review'] = perms['read'] | perms['=review']
perms['open'] = perms['read'] | perms['=open']
perms['write'] = perms['open'] | perms['=write']
# does 'admin' include 'review'?
perms['admin'] = perms['write'] | perms['=admin']
# and does 'owner' include 'admin'?
perms['owner'] = perms['=owner']  # not sure about this
perms['super'] = perms['admin'] | perms['review'] | perms['=super']

def _main():
  # type: () -> None
  if '--test' in sys.argv:
    test_perms()
    print('A-OK!')
    return

  # Parse args.
  argp = argparse.ArgumentParser(description='Run protection table checks.')
  argp.add_argument('-i', 
    dest='input', help='Input filename for protect table', required=True)
  argp.add_argument('-u', 
    dest='user', help='User to check', required=True)
  argp.add_argument('-p', 
    dest='perm', help='Permission level to check', required=True)
  argp.add_argument('-g',
    # This is so you can pass a list of groups the user is a member of.
    dest='groups', help='Group(s) to include', action='append')
  argp.add_argument('path',
    help='Depot path to check')
  args = argp.parse_args()

  # Build map from file.
  f = open(args.input, 'r')
  map = build_protection_map(f.read(), args.perm, args.user, args.groups)

  # Check against path and print stuff.
  print("%s's %s protections mapping:" % (args.user, args.perm))
  print(map)
  print("includes %s? %s" % (args.path, map.includes(args.path)))

def build_protection_map(form, perm, user, groups=None):
  # type: (str, str, str, Optional[List[str]]) -> P4.Map

  spec = P4.P4().parse_protect(form)
  map = P4.Map()
  
  for line in spec._Protections:
    lvl, type, name, _, path = shlex.split(line)

    # Check to see if this line is applicable to our protection map.

    # Some subtlety here: exclusions remove ALL levels
    # UNLESS they're specified as an =level
    if perm not in perms[lvl] and \
          (not path.startswith('-') or lvl.startswith('=')):
      continue

    if type == 'user' and name != user and name != '*':
        continue
    if type == 'group' and (not groups or name not in groups and name != '*'):
        continue

    # shlex.split removes quotes -- add them back in now for Map.
    map.insert('"' + path + '"')

  return map

def test_perms():
  # type: () -> None
  form = """
Protections:
	list user bob * //list/...
	read user bob * //read/...
	read user bob * -//read/secret/...
	write user bob * //write/...
	=write user * * -//write/protected/...
	admin user bob * //admin/...
	super user bob * //super/...
	read group * * //groups/all/...
	read group peeps * //groups/peeps/...
	read group folks * //groups/folks/...
"""
  map = build_protection_map(form, 'list', 'bob')
  assert map.includes('//read/foo')
  assert map.includes('//write/protected/foo')
  assert not map.includes('//read/secret/foo')
  assert not map.includes('//groups/foo')

  map = build_protection_map(form, 'write', 'bob')
  assert map.includes('//admin/foo')
  assert not map.includes('//write/protected/foo')

  map = build_protection_map(form, 'read', 'biff', ['peeps'])
  assert map.includes('//groups/all/foo')
  assert map.includes('//groups/peeps/foo')
  assert not map.includes('//groups/folks/foo')

if __name__ == "__main__":
  _main()
# Change User Description Committed
#2 23840 Sam Stafford Fix up groups.
#1 23839 Sam Stafford Rearrange things a bit so this is a bit more useful as a Python module.
//guest/sam_stafford/scripts/protect_preview.py
#2 23832 Sam Stafford Fix up some comments.
#1 23831 Sam Stafford Toy script to simulate effects of a protection table client-side.