Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 39 additions & 11 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,26 +42,54 @@ runs:
- name: Setup and start PostgreSQL
run: |
export PGDATA="$RUNNER_TEMP/pgdata"
pg_ctl init --options="--encoding=UTF-8 --locale=en_US.UTF-8"
export PWFILE="$RUNNER_TEMP/pwfile"

# Forbid creating unix sockets since they are created by default in the
# directory we don't have permissions to.
echo "unix_socket_directories = ''" >> "$PGDATA/postgresql.conf"
echo "port = ${{ inputs.port }}" >> "$PGDATA/postgresql.conf"
# Save user password on disk so we can create a new PostgreSQL database
# cluster. Password must be set because we're turning 'trust'
# authentication off, and there's no other option since this script is
# not executed interactively.
echo '${{ inputs.password }}' > $PWFILE

# There are couple of reasons why we need to create a new PostgreSQL
# database cluster:
#
# * TODO
# --auth="scram-sha-256" \
initdb \
--username="${{ inputs.username }}" \
--pwfile="$PWFILE" \
--auth-local="trust" \
--auth-host="scram-sha-256" \
--encoding="UTF-8" \
--locale="en_US.UTF-8" \
--no-instructions

cat <<EOF > "$PGDATA/postgresql.conf"
port = ${{ inputs.port }}
EOF

# Client authentication is controlled by a host-based authentication
# configuration file. By default local connections are trusted and do
# not require password (in fact, passwords are ignored). It's undesired
# behaviour in our case since in case of CI we want to make sure that
# the password is configured and passed properly by the application
# under test.
# cat <<EOF > "$PGDATA/pg_hba.conf"
# host all all all scram-sha-256
# EOF
pg_ctl start

# Both PGHOST and PGUSER are used by PostgreSQL tooling such as 'psql'
# or 'createuser'. Since PostgreSQL data has been resetup, we cannot
# or 'createuser'. Since PostgreSQL data has been recreated, we cannot
# rely on defaults anymore.
#
# PGHOST is required for Linux and macOS since they default to unix
# sockets, and we have turned them off.
#
# PGUSER is required for Windows since default the tooling's default
# user is 'postgres', while 'pg_ctl init' creates one with the name of
# the current user.
echo "PGHOST=localhost" >> $GITHUB_ENV
echo "PGUSER=${USER:-$USERNAME}" >> $GITHUB_ENV
# PGUSER is required for Windows since default tooling user is
# 'postgres', while 'pg_ctl init' creates one with the name of the
# current user.
#echo "PGHOST=localhost" >> $GITHUB_ENV
echo "PGPORT=${{ inputs.port }}" >> $GITHUB_ENV
shell: bash

Expand Down
45 changes: 44 additions & 1 deletion test_action.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import typing as t
import os
import typing as t
import urllib.parse

import psycopg
import pytest
Expand Down Expand Up @@ -91,3 +92,45 @@ def test_user_create_drop_database(connection: psycopg.Connection):
database_name = "foobar42"
connection.execute(f"CREATE DATABASE {database_name}")
connection.execute(f"DROP DATABASE {database_name}")


def test_auth_wrong_username(connection_factory: t.Callable[[str], psycopg.Connection]):
"""Test that wrong username is rejected!"""

connection_uri = os.getenv("CONNECTION_URI")
connection_parts = urllib.parse.urlparse(connection_uri)

# Despite of exposting username/password of network location, poor Python
# doesn't allow their modification. Thus we have to have these dances in
# order to change the password in the connection URI.
userinfo, _, hostinfo = connection_parts.netloc.rpartition("@")
_ , _, password = userinfo.rpartition(":")
connection_parts = connection_parts._replace(netloc=f"bruteforce:{password}@{hostinfo}")
connection_uri = urllib.parse.urlunparse(connection_parts)

with pytest.raises(psycopg.OperationalError) as excinfo:
test_user_create_insert_select(connection_factory(connection_uri))
assert str(excinfo.value) == (
f'connection failed: FATAL: password authentication failed for user "bruteforce"'
)


def test_auth_wrong_password(connection_factory: t.Callable[[str], psycopg.Connection]):
"""Test that wrong password is rejected!"""

connection_uri = os.getenv("CONNECTION_URI")
connection_parts = urllib.parse.urlparse(connection_uri)

# Despite of exposting username/password of network location, poor Python
# doesn't allow their modification. Thus we have to have these dances in
# order to change the password in the connection URI.
userinfo, _, hostinfo = connection_parts.netloc.rpartition("@")
username, _, _ = userinfo.rpartition(":")
connection_parts = connection_parts._replace(netloc=f"{username}:bruteforce@{hostinfo}")
connection_uri = urllib.parse.urlunparse(connection_parts)

with pytest.raises(psycopg.OperationalError) as excinfo:
test_user_create_insert_select(connection_factory(connection_uri))
assert str(excinfo.value) == (
f'connection failed: FATAL: password authentication failed for user "{username}"'
)