Skip to content

Commit

Permalink
Install GRR sdists from GCS when building the demo docker image, depr…
Browse files Browse the repository at this point in the history
…ecate Email.link_regex config option.
  • Loading branch information
ogarod committed Aug 28, 2017
1 parent 972bd49 commit c6a250c
Show file tree
Hide file tree
Showing 13 changed files with 216 additions and 164 deletions.
2 changes: 0 additions & 2 deletions .dockerignore
Expand Up @@ -14,8 +14,6 @@
*_pb2.*
*/*_pb2.*
*/*/*_pb2.*
.git
.gitignore
ACKNOWLEDGEMENTS
AUTHORS
build
Expand Down
6 changes: 5 additions & 1 deletion .travis.yml
Expand Up @@ -271,7 +271,11 @@ matrix:
sudo docker exec "${DOCKER_CONTAINER}"
travis/build_server_deb.sh && # Needs to be run as root.
travis/deploy_to_gcs.sh
travis/deploy_to_gcs.sh &&
# Trigger build of a new GRR Docker image (grrdocker/grr)
# See https://hub.docker.com/r/grrdocker/grr/~/settings/automated-builds/
curl -H "Content-Type: application/json" --data '{"docker_tag": "latest"}' -X POST https://registry.hub.docker.com/u/grrdocker/grr/trigger/4499c4d4-4a8b-48da-bc95-5dbab39be545/
cache:
directories:
Expand Down
59 changes: 26 additions & 33 deletions Dockerfile
@@ -1,13 +1,28 @@
# A Docker container capable of running all GRR components.
# A Docker image capable of running all GRR components.
#
# See https://hub.docker.com/r/grrdocker/grr/
#
# We have configured Travis to trigger an image build every time a new server
# deb is been uploaded to GCS.
#
# Run the container with:
#
# docker run \
# -e EXTERNAL_HOSTNAME="localhost" \
# -e ADMIN_PASSWORD="demo" \
# -p 0.0.0.0:8000:8000 \
# -p 0.0.0.0:8080:8080 \
# grrdocker/grr

FROM ubuntu:xenial

LABEL maintainer="grr-dev@googlegroups.com"

SHELL ["/bin/bash", "-c"]

ENV GRR_VENV /usr/share/grr-server
ENV PROTOC /usr/share/protobuf/bin/protoc

SHELL ["/bin/bash", "-c"]

RUN apt-get update && \
apt-get install -y \
debhelper \
Expand All @@ -22,50 +37,28 @@ RUN apt-get update && \
wget \
zip

RUN pip install --upgrade pip virtualenv
RUN pip install --upgrade --no-cache-dir pip virtualenv && virtualenv $GRR_VENV

# Install proto compiler
RUN mkdir -p /usr/share/protobuf && \
cd /usr/share/protobuf && \
wget --quiet "https://github.com/google/protobuf/releases/download/v3.3.0/protoc-3.3.0-linux-x86_64.zip" && \
unzip protoc-3.3.0-linux-x86_64.zip

# Make sure Bower will be able to run as root.
# Install nodeenv, a prebuilt version of NodeJS and update the virtualenv
# environment.
# Pull dependencies and templates from pypi and build wheels so docker can cache
# them. This just makes the actual install go faster.
RUN echo '{ "allow_root": true }' > /root/.bowerrc

RUN virtualenv $GRR_VENV

RUN $GRR_VENV/bin/pip install --upgrade wheel six setuptools nodeenv
unzip protoc-3.3.0-linux-x86_64.zip && \
rm protoc-3.3.0-linux-x86_64.zip

# TODO(ogaro) Stop hard-coding the node version to install
# when a Linux node-sass binary compatible with node v8.0.0 is
# available: https://github.com/sass/node-sass/pull/1969
RUN $GRR_VENV/bin/nodeenv -p --prebuilt --node=7.10.0
RUN $GRR_VENV/bin/pip install --upgrade --no-cache-dir wheel six setuptools nodeenv && \
$GRR_VENV/bin/nodeenv -p --prebuilt --node=7.10.0 && \
echo '{ "allow_root": true }' > /root/.bowerrc

# Copy the GRR code over.
ADD . /usr/src/grr

WORKDIR /usr/src/grr

RUN source $GRR_VENV/bin/activate && python setup.py sdist --formats=zip --dist-dir=/sdists --no-make-docs

RUN $GRR_VENV/bin/python grr/config/grr-response-client/setup.py sdist --formats=zip --dist-dir=/sdists

RUN $GRR_VENV/bin/python api_client/python/setup.py sdist --formats=zip --dist-dir=/sdists

RUN $GRR_VENV/bin/python grr/config/grr-response-server/setup.py sdist --formats=zip --dist-dir=/sdists

RUN $GRR_VENV/bin/pip install --find-links=/sdists /sdists/grr-response-server-*.zip

WORKDIR /

COPY scripts/docker-entrypoint.sh .
RUN cd /usr/src/grr && /usr/src/grr/docker/install_grr_from_gcs.sh

ENTRYPOINT ["/docker-entrypoint.sh"]
ENTRYPOINT ["/usr/src/grr/scripts/docker-entrypoint.sh"]

# Port for the admin UI GUI
EXPOSE 8000
Expand Down
2 changes: 0 additions & 2 deletions grr/config/grr-response-test/test_data/grr_test.yaml
Expand Up @@ -221,8 +221,6 @@ Client.server_urls: ["http://localhost:8080/"]

Test Context:
AdminUI.webauth_manager: NullWebAuthManager
# This is needed to ensure the logic works in Selenium tests.
Email.link_regex_list: ['%{(?P<link>(b)\/\d+)}']

Client.poll_max: 5
Logging.path: /tmp/grr_logs/
Expand Down
6 changes: 0 additions & 6 deletions grr/config/server.py
Expand Up @@ -181,12 +181,6 @@
"If you feel like it, you can add a funny cat picture to approval mails. "
"Needs full html: <img src=\"https://imgur.com/path/to/cat.jpg\">.")

config_lib.DEFINE_list(
"Email.link_regex_list", [],
"Strings matching these regexes in approval reasons will be turned into "
" HTML links in approval emails. Note you have to use single quoted strings"
" when setting this variable to prevent escaping.")

config_lib.DEFINE_string(
"StatsStore.process_id",
default="",
Expand Down
208 changes: 154 additions & 54 deletions grr/gui/selenium_tests/email_links_test.py
Expand Up @@ -23,6 +23,32 @@

class TestEmailLinks(gui_test_lib.GRRSeleniumTest):

APPROVAL_REASON = "Please please let me"
GRANTOR_TOKEN = access_control.ACLToken(
username="igrantapproval", reason="test")

def setUp(self):
super(TestEmailLinks, self).setUp()

self.messages_sent = []

def SendEmailStub(unused_from_user, unused_to_user, unused_subject, message,
**unused_kwargs):
self.messages_sent.append(message)

self.email_stubber = utils.Stubber(email_alerts.EMAIL_ALERTER, "SendEmail",
SendEmailStub)
self.email_stubber.Start()

def tearDown(self):
super(TestEmailLinks, self).tearDown()
self.email_stubber.Stop()

def _ExtractLinkFromMessage(self, message):
m = re.search(r"href='(.+?)'", message, re.MULTILINE)
link = urlparse.urlparse(m.group(1))
return link.path + "/" + "#" + link.fragment

def CreateSampleHunt(self, token=None):
client_rule_set = rdf_foreman.ForemanClientRuleSet(rules=[
rdf_foreman.ForemanClientRule(
Expand All @@ -43,98 +69,172 @@ def CreateSampleHunt(self, token=None):
def testEmailClientApprovalRequestLinkLeadsToACorrectPage(self):
client_id = self.SetupClients(1)[0]

messages_sent = []
security.ClientApprovalRequestor(
reason="Please please let me",
subject_urn=client_id,
approver=self.GRANTOR_TOKEN.username,
token=self.token).Request()

def SendEmailStub(unused_from_user, unused_to_user, unused_subject, message,
**unused_kwargs):
messages_sent.append(message)
self.assertEqual(len(self.messages_sent), 1)
message = self.messages_sent[0]

# Request client approval, it will trigger an email message.
with utils.Stubber(email_alerts.EMAIL_ALERTER, "SendEmail", SendEmailStub):
security.ClientApprovalRequestor(
reason="Please please let me",
subject_urn=client_id,
approver=self.token.username,
token=access_control.ACLToken(
username="iwantapproval", reason="test")).Request()
self.assertEqual(len(messages_sent), 1)
self.assertTrue(self.APPROVAL_REASON in message)
self.assertTrue(self.token.username in message)
self.assertTrue(client_id.Basename() in message)

# Extract link from the message text and open it.
m = re.search(r"href='(.+?)'", messages_sent[0], re.MULTILINE)
link = urlparse.urlparse(m.group(1))
self.Open(link.path + "?" + link.query + "#" + link.fragment)
self.Open(self._ExtractLinkFromMessage(message))

# Check that requestor's username and reason are correctly displayed.
self.WaitUntil(self.IsTextPresent, "iwantapproval")
self.WaitUntil(self.IsTextPresent, "Please please let me")
self.WaitUntil(self.IsTextPresent, self.token.username)
self.WaitUntil(self.IsTextPresent, self.APPROVAL_REASON)
# Check that host information is displayed.
self.WaitUntil(self.IsTextPresent, client_id.Basename())
self.WaitUntil(self.IsTextPresent, "Host-0")

def testEmailClientApprovalGrantNotificationLinkLeadsToACorrectPage(self):
client_id = self.SetupClients(1)[0]

security.ClientApprovalRequestor(
reason=self.APPROVAL_REASON,
subject_urn=client_id,
approver=self.GRANTOR_TOKEN.username,
token=self.token).Request()
security.ClientApprovalGrantor(
reason=self.APPROVAL_REASON,
subject_urn=client_id,
token=self.GRANTOR_TOKEN,
delegate=self.token.username).Grant()

# There should be 1 message for approval request and 1 message
# for approval grant notification.
self.assertEqual(len(self.messages_sent), 2)

message = self.messages_sent[1]

self.assertTrue(self.APPROVAL_REASON in message)
self.assertTrue(self.GRANTOR_TOKEN.username in message)
self.assertTrue(client_id.Basename() in message)

self.Open(self._ExtractLinkFromMessage(message))

# We should end up on client's page. Check that host information is
# displayed.
self.WaitUntil(self.IsTextPresent, client_id.Basename())
self.WaitUntil(self.IsTextPresent, "Host-0")
# Check that the reason is displayed.
self.WaitUntil(self.IsTextPresent, self.APPROVAL_REASON)

def testEmailHuntApprovalRequestLinkLeadsToACorrectPage(self):
hunt_id = self.CreateSampleHunt()

messages_sent = []
# Request client approval, it will trigger an email message.
security.HuntApprovalRequestor(
reason=self.APPROVAL_REASON,
subject_urn=hunt_id,
approver=self.GRANTOR_TOKEN.username,
token=self.token).Request()

def SendEmailStub(unused_from_user, unused_to_user, unused_subject, message,
**unused_kwargs):
messages_sent.append(message)
self.assertEqual(len(self.messages_sent), 1)
message = self.messages_sent[0]

# Request client approval, it will trigger an email message.
with utils.Stubber(email_alerts.EMAIL_ALERTER, "SendEmail", SendEmailStub):
security.HuntApprovalRequestor(
reason="Please please let me",
subject_urn=hunt_id,
approver=self.token.username,
token=access_control.ACLToken(
username="iwantapproval", reason="test")).Request()
self.assertEqual(len(messages_sent), 1)
self.assertTrue(self.APPROVAL_REASON in message)
self.assertTrue(self.token.username in message)
self.assertTrue(hunt_id.Basename() in message)

# Extract link from the message text and open it.
m = re.search(r"href='(.+?)'", messages_sent[0], re.MULTILINE)
link = urlparse.urlparse(m.group(1))
self.Open(link.path + "?" + link.query + "#" + link.fragment)
self.Open(self._ExtractLinkFromMessage(message))

# Check that requestor's username and reason are correctly displayed.
self.WaitUntil(self.IsTextPresent, "iwantapproval")
self.WaitUntil(self.IsTextPresent, "Please please let me")
self.WaitUntil(self.IsTextPresent, self.token.username)
self.WaitUntil(self.IsTextPresent, self.APPROVAL_REASON)
# Check that host information is displayed.
self.WaitUntil(self.IsTextPresent, str(hunt_id))
self.WaitUntil(self.IsTextPresent, "SampleHunt")

def testEmailHuntApprovalGrantNotificationLinkLeadsToCorrectPage(self):
hunt_id = self.CreateSampleHunt()

security.HuntApprovalRequestor(
reason=self.APPROVAL_REASON,
subject_urn=hunt_id,
approver=self.GRANTOR_TOKEN.username,
token=self.token).Request()
security.HuntApprovalGrantor(
reason=self.APPROVAL_REASON,
subject_urn=hunt_id,
token=self.GRANTOR_TOKEN,
delegate=self.token.username).Grant()

# There should be 1 message for approval request and 1 message
# for approval grant notification.
self.assertEqual(len(self.messages_sent), 2)

message = self.messages_sent[1]
self.assertTrue(self.APPROVAL_REASON in message)
self.assertTrue(self.GRANTOR_TOKEN.username in message)
self.assertTrue(hunt_id.Basename() in message)

self.Open(self._ExtractLinkFromMessage(message))

# We should end up on hunts's page.
self.WaitUntil(self.IsTextPresent, hunt_id.Basename())

def testEmailCronJobApprovalRequestLinkLeadsToACorrectPage(self):
cronjobs.ScheduleSystemCronFlows(
names=[cron_system.OSBreakDown.__name__], token=self.token)
cronjobs.CRON_MANAGER.DisableJob(rdfvalue.RDFURN("aff4:/cron/OSBreakDown"))

messages_sent = []
security.CronJobApprovalRequestor(
reason=self.APPROVAL_REASON,
subject_urn="aff4:/cron/OSBreakDown",
approver=self.GRANTOR_TOKEN.username,
token=self.token).Request()

def SendEmailStub(unused_from_user, unused_to_user, unused_subject, message,
**unused_kwargs):
messages_sent.append(message)
self.assertEqual(len(self.messages_sent), 1)
message = self.messages_sent[0]

# Request client approval, it will trigger an email message.
with utils.Stubber(email_alerts.EMAIL_ALERTER, "SendEmail", SendEmailStub):
security.CronJobApprovalRequestor(
reason="Please please let me",
subject_urn="aff4:/cron/OSBreakDown",
approver=self.token.username,
token=access_control.ACLToken(
username="iwantapproval", reason="test")).Request()
self.assertEqual(len(messages_sent), 1)
self.assertTrue(self.APPROVAL_REASON in message)
self.assertTrue(self.token.username in message)
self.assertTrue("OSBreakDown" in message)

# Extract link from the message text and open it.
m = re.search(r"href='(.+?)'", messages_sent[0], re.MULTILINE)
m = re.search(r"href='(.+?)'", message, re.MULTILINE)
link = urlparse.urlparse(m.group(1))
self.Open(link.path + "?" + link.query + "#" + link.fragment)

# Check that requestor's username and reason are correctly displayed.
self.WaitUntil(self.IsTextPresent, "iwantapproval")
self.WaitUntil(self.IsTextPresent, "Please please let me")
self.WaitUntil(self.IsTextPresent, self.token.username)
self.WaitUntil(self.IsTextPresent, self.APPROVAL_REASON)
# Check that host information is displayed.
self.WaitUntil(self.IsTextPresent, cron_system.OSBreakDown.__name__)
self.WaitUntil(self.IsTextPresent, "Periodicity")

def testEmailCronjobApprovalGrantNotificationLinkLeadsToCorrectPage(self):
cronjobs.ScheduleSystemCronFlows(
names=[cron_system.OSBreakDown.__name__], token=self.token)
cronjobs.CRON_MANAGER.DisableJob(rdfvalue.RDFURN("aff4:/cron/OSBreakDown"))

security.CronJobApprovalRequestor(
reason=self.APPROVAL_REASON,
subject_urn="aff4:/cron/OSBreakDown",
approver=self.GRANTOR_TOKEN.username,
token=self.token).Request()
security.CronJobApprovalGrantor(
reason=self.APPROVAL_REASON,
subject_urn="aff4:/cron/OSBreakDown",
token=self.GRANTOR_TOKEN,
delegate=self.token.username).Grant()

# There should be 1 message for approval request and 1 message
# for approval grant notification.
self.assertEqual(len(self.messages_sent), 2)
message = self.messages_sent[1]
self.assertTrue(self.APPROVAL_REASON in message)
self.assertTrue(self.GRANTOR_TOKEN.username in message)

self.Open(self._ExtractLinkFromMessage(message))

self.WaitUntil(self.IsTextPresent, "OSBreakDown")


def main(argv):
del argv # Unused.
Expand Down

0 comments on commit c6a250c

Please sign in to comment.