click-apparmor
--------------

click-apparmor provides the AppArmor hook for click packaging. The hook is
defined in /usr/share/click/hooks/apparmor.hook. Click packaging uses a
declarative json manifest to define the AppArmor policy for the package and the
click AppArmor hook is responsible for taking this json manifest and converting
it into an AppArmor profile to load into the kernel. This happens in several
steps:

 1. click calls the AppArmor hook, aa-clickhook (as defined by 'Exec' in the
    click hook), and determines which manifests to operate on
 2. for each manifest, aa-clickhook converts the manifest into an easyprof
    json file
 3. for each easyprof manifest, aa-clickhook uses AppArmor easyprof to
    generate an AppArmor profile
 4. for each AppArmor profile, aa-clickhook stores the profile on the system
    so it is persistant across reboots
 5. for each AppArmor profile, aa-clickhook loads the profile into the kernel
 6. if there are any profiles defined without a corresponding json manifest,
    aa-clickhook will remove them from the system

Important locations:
 * /var/lib/apparmor/clicks
   - location of json manifests as defined by 'Pattern' in the click hook
 * /var/lib/apparmor/profiles
   - location of translated AppArmor profiles
 * /var/cache/apparmor
   - location of cached AppArmor profiles


aa-clicktool is also provided for testing. To use:

1. Copy your click manifest and click security manifest somewhere in a manner
   that aa-clicktool can use (note, $name_$application_$version needs to match
   with what is in the manifests). Eg:

   $ mkdir -p /tmp/debug/com.ubuntu.developer.username.myapp/0.1/apparmor \
              /tmp/debug/com.ubuntu.developer.username.myapp/0.1/.click/info
   $ cp apparmor/myapp.json \
        /tmp/debug/com.ubuntu.developer.username.myapp/0.1/apparmor/
   $ cp ./manifest.json \
        /tmp/debug/com.ubuntu.developer.username.myapp/0.1/.click/info/com.ubuntu.developer.username.myapp_myapp_0.1.json
   $ ln -s /tmp/debug/com.ubuntu.developer.username.myapp/0.1/apparmor/myapp.json \
           /tmp/debug/com.ubuntu.developer.username.myapp_myapp_0.1.json

2. Run aa-clicktool on it:
   $ aa-clicktool -o /tmp/debug/easyprof.json \
                     /tmp/debug/com.ubuntu.developer.username.myapp_myapp_0.1.json

3. Generate the apparmor profile with aa-easyprof:
   $ aa-easyprof -m /tmp/debug/easyprof.json > /tmp/debug/profile

4. Load the profile in the usual way:
   $ sudo apparmor_parser -r /tmp/debug/profile


Development
-----------
$ sudo apt-get build-dep click-apparmor

Run tests with:
$ ./test-clicktool.py

or:
$ make test

Run with policy load tests:
$ sudo ./test-clicktool.py

or:
$ sudo make test

Run with coverage:
$ sudo python3 -m coverage run ./test-clicktool.py
$ python3 -m coverage report --show-missing apparmor/click.py

or:
$ sudo make coverage
$ make coverage-report


In addition to the above, before committing your changes, please run:
$ make check


If you are going to develop click-apparmor regularly, you might want to add a
bzr hook to run the testsuite before committing. Eg, add something like this to
~/.bazaar/plugins/hooks/__init__.py:

  #!/usr/bin/python
  from bzrlib.branch import Branch

  def run_tests_click_apparmor(local, master, old_revno, old_revid, new_revno,
                               new_revid, seven, eight):
      #print local, master, old_revno, old_revid, new_revno, new_revid, seven, eight
      if 'click-apparmor' in master.base:
          import subprocess
          print ''
          rc = subprocess.call(['make', 'check'])
          if rc != 0:
              import sys
              sys.exit(1)

  Branch.hooks.install_named_hook('pre_commit',
                                  run_tests_click_apparmor,
                                  'click-apparmor tests')

Adding new frameworks
---------------------
Adjust framework_transforms in src/apparmor/click.py to have the new framework
and policy version for that framework. Eg, to add 'ubuntu-sdk-15.04' based
frameworks to use version 1.3 of the policy, update this:
framework_transforms = {
    "ubuntu-sdk-13.10": (_ubuntu_transform, 1.0),
    "ubuntu-sdk-14.04": (_ubuntu_transform, 1.1),
    "ubuntu-sdk-14.10": (_ubuntu_transform, 1.2),
}

to be:
framework_transforms = {
    "ubuntu-sdk-13.10": (_ubuntu_transform, 1.0),
    "ubuntu-sdk-14.04": (_ubuntu_transform, 1.1),
    "ubuntu-sdk-14.10": (_ubuntu_transform, 1.2),
    "ubuntu-sdk-15.04": (_ubuntu_transform, 1.3),
}

