Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release v7.3.0 #2294

Merged
merged 68 commits into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
90d3d15
Bump cfn-lint from 0.87.1 to 0.87.2
dependabot[bot] May 13, 2024
748b034
Bump cryptography from 42.0.5 to 42.0.7
dependabot[bot] May 13, 2024
726d6c9
Bump moto[dynamodb] from 5.0.6 to 5.0.7
dependabot[bot] May 13, 2024
b976853
Bump actions/checkout from 4.1.2 to 4.1.5
dependabot[bot] May 13, 2024
7e993de
binary media types for RestAPI
jtherrmann May 13, 2024
a6ffc3e
Merge pull request #2279 from ASFHyP3/binary-media-types
jtherrmann May 13, 2024
2ae98fb
Revert "binary media types for RestAPI"
jake-herrmann May 15, 2024
84444e0
Merge pull request #2282 from ASFHyP3/revert-2279-binary-media-types
jtherrmann May 15, 2024
071936b
Merge branch 'develop' into dependabot/pip/moto-dynamodb--5.0.7
jtherrmann May 16, 2024
d8ce866
Merge pull request #2275 from ASFHyP3/dependabot/pip/moto-dynamodb--5…
jtherrmann May 16, 2024
2cb3cce
Merge branch 'develop' into dependabot/github_actions/actions/checkou…
jtherrmann May 16, 2024
2d275ab
Bump boto3 from 1.34.100 to 1.34.106
dependabot[bot] May 16, 2024
9c0d531
Merge pull request #2277 from ASFHyP3/dependabot/github_actions/actio…
jtherrmann May 16, 2024
3f0a68c
Merge branch 'develop' into dependabot/pip/cryptography-42.0.7
jtherrmann May 16, 2024
0db60d7
Merge pull request #2274 from ASFHyP3/dependabot/pip/cryptography-42.0.7
jtherrmann May 16, 2024
c440d07
Merge branch 'develop' into dependabot/pip/cfn-lint-0.87.2
jtherrmann May 16, 2024
c70d1ca
Merge pull request #2273 from ASFHyP3/dependabot/pip/cfn-lint-0.87.2
jtherrmann May 16, 2024
4dc4d75
Merge pull request #2284 from ASFHyP3/dependabot/pip/boto3-1.34.106
jtherrmann May 16, 2024
01a028b
first draft of access codes implementation
jtherrmann May 20, 2024
9b73490
pass AccessCodesTable name to API stack, add a TODO
jtherrmann May 20, 2024
80fd79f
add access codes table to cfg.env, add a TODO
jtherrmann May 20, 2024
c758ea0
add a TODO
jtherrmann May 20, 2024
7bc7dc9
---
dependabot[bot] May 20, 2024
79c6308
---
dependabot[bot] May 20, 2024
70bb9c4
---
dependabot[bot] May 20, 2024
7c006d2
---
dependabot[bot] May 20, 2024
e3a75ba
add access_code to user record
jtherrmann May 20, 2024
53a98a6
Merge pull request #2291 from ASFHyP3/dependabot/pip/serverless-wsgi-…
jtherrmann May 21, 2024
c732eb2
Merge pull request #2290 from ASFHyP3/dependabot/pip/cfn-lint-0.87.3
jtherrmann May 21, 2024
2868040
---
dependabot[bot] May 21, 2024
a10f094
Merge pull request #2292 from ASFHyP3/dependabot/pip/requests-2.32.1
jtherrmann May 21, 2024
dc20b64
Merge pull request #2288 from ASFHyP3/dependabot/pip/boto3-1.34.109
jtherrmann May 21, 2024
2cd6619
---
dependabot[bot] May 21, 2024
8215df8
Merge pull request #2286 from ASFHyP3/dependabot/github_actions/actio…
jtherrmann May 21, 2024
c552d35
Merge pull request #2287 from ASFHyP3/dependabot/pip/pytest-8.2.1
jtherrmann May 21, 2024
66b5328
remove a TODO
jtherrmann May 21, 2024
f366a10
mock access codes table
jtherrmann May 21, 2024
31580c0
factor out a dynamo.util.current_time function
jtherrmann May 21, 2024
9edf91c
add test_update_user_access_code
jtherrmann May 21, 2024
c49a217
add a todo
jtherrmann May 21, 2024
e99a071
split into multiple tests
jtherrmann May 22, 2024
86934e5
add test_patch_user_access_code
jtherrmann May 22, 2024
6fd2570
add test_patch_user_access_code_expired
jtherrmann May 22, 2024
30909b4
add test_patch_user_access_code_invalid
jtherrmann May 22, 2024
4f6b71e
remove default_credits parameter from _reset_credits_if_needed
jtherrmann May 22, 2024
31231e6
refactor update_user to call _reset_credits_if_needed
jtherrmann May 22, 2024
a957251
changelog
jtherrmann May 22, 2024
565dda3
Merge branch 'develop' into access-codes
jtherrmann May 22, 2024
6c006f2
unused import
jtherrmann May 22, 2024
093257c
Merge branch 'access-codes' of github.com:ASFHyP3/hyp3 into access-codes
jtherrmann May 22, 2024
3222602
rename `expires` field to `end_date`
jtherrmann May 23, 2024
ff9a7f6
allow any string for access_code
jtherrmann May 23, 2024
7992fac
Update lib/dynamo/dynamo/user.py
jtherrmann May 23, 2024
a53bce2
rename function
jtherrmann May 23, 2024
adf2e8a
rename some tests
jtherrmann May 23, 2024
b76294d
rename function in mocks
jtherrmann May 23, 2024
5e4edee
add start_date for access codes
jtherrmann May 23, 2024
d3ac85c
update changelog
jtherrmann May 23, 2024
0a5e957
Merge pull request #2285 from ASFHyP3/access-codes
jtherrmann May 23, 2024
e2ddd84
Update deploy-enterprise.yml
cmarshak May 23, 2024
519f05d
Merge branch 'ASFHyP3:develop' into cmarshak-patch-1
cmarshak May 23, 2024
1e24948
Update CHANGELOG.md
cmarshak May 23, 2024
dd505cb
Update CHANGELOG.md
cmarshak May 23, 2024
654785a
Update deploy-enterprise.yml
cmarshak May 23, 2024
3fde96e
Merge pull request #2293 from ACCESS-Cloud-Based-InSAR/cmarshak-patch-1
jtherrmann May 23, 2024
c9a6043
fix changelog
jtherrmann May 23, 2024
decdc0c
fix changelog again
jtherrmann May 23, 2024
6e0606a
Merge pull request #2295 from ASFHyP3/fix-changelog-3
jtherrmann May 23, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/deploy-daac.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ jobs:
url: https://${{ matrix.domain }}

steps:
- uses: actions/[email protected].5
- uses: actions/[email protected].6

- uses: aws-actions/configure-aws-credentials@v4
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/deploy-enterprise-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ jobs:
url: https://${{ matrix.domain }}

steps:
- uses: actions/[email protected].5
- uses: actions/[email protected].6

- uses: aws-actions/configure-aws-credentials@v4
with:
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/deploy-enterprise.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,16 @@ jobs:
domain: hyp3-a19-jpl.asf.alaska.edu
template_bucket: cf-templates-v4pvone059de-us-west-2
image_tag: latest
product_lifetime_in_days: 180
product_lifetime_in_days: 14
default_credits_per_user: 0
default_application_status: APPROVED
cost_profile: DEFAULT
job_files: >-
job_spec/ARIA_RAIDER.yml
job_spec/INSAR_ISCE.yml
instance_types: c6id.xlarge,c6id.2xlarge,c6id.4xlarge,c6id.8xlarge
default_max_vcpus: 4000
expanded_max_vcpus: 4000
default_max_vcpus: 0
expanded_max_vcpus: 0
required_surplus: 0
security_environment: JPL-public
ami_id: /aws/service/ecs/optimized-ami/amazon-linux-2023/recommended/image_id
Expand Down Expand Up @@ -229,7 +229,7 @@ jobs:
url: https://${{ matrix.domain }}

steps:
- uses: actions/[email protected].5
- uses: actions/[email protected].6

- uses: aws-actions/configure-aws-credentials@v4
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/deploy-whitelisting-sandbox.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ jobs:
url: https://${{ matrix.domain }}

steps:
- uses: actions/[email protected].2
- uses: actions/[email protected].6

- uses: aws-actions/configure-aws-credentials@v4
with:
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/static-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
flake8:
runs-on: ubuntu-latest
steps:
- uses: actions/[email protected].5
- uses: actions/[email protected].6
- uses: actions/setup-python@v5
with:
python-version: 3.9
Expand All @@ -23,7 +23,7 @@ jobs:
matrix:
security_environment: [ASF, EDC, JPL, JPL-public]
steps:
- uses: actions/[email protected].5
- uses: actions/[email protected].6
- uses: actions/setup-python@v5
with:
python-version: 3.9
Expand All @@ -37,7 +37,7 @@ jobs:
openapi-spec-validator:
runs-on: ubuntu-latest
steps:
- uses: actions/[email protected].5
- uses: actions/[email protected].6
- uses: actions/setup-python@v5
with:
python-version: 3.9
Expand All @@ -50,7 +50,7 @@ jobs:
statelint:
runs-on: ubuntu-latest
steps:
- uses: actions/[email protected].5
- uses: actions/[email protected].6
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.7
Expand All @@ -70,7 +70,7 @@ jobs:
snyk:
runs-on: ubuntu-latest
steps:
- uses: actions/[email protected].5
- uses: actions/[email protected].6
- uses: snyk/actions/[email protected]
- uses: actions/setup-python@v5
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/[email protected].5
- uses: actions/[email protected].6

- uses: actions/setup-python@v5
with:
Expand Down
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [7.3.0]

This release adds support for access codes. If a user specifies an active access code when they apply for HyP3 access, they will be granted automatic approval without the need for a HyP3 operator to review their application.

If you operate a HyP3 deployment, you can create a new access code by adding an item to the `AccessCodesTable` DynamoDB table for your deployment, with any string for the `access_code` attribute and an ISO-formatted UTC timestamp for the `start_date` and `end_date` attributes, e.g. `2024-06-01T00:00:00+00:00` and `2024-06-02T00:00:00+00:00` for an access code that becomes active on June 1, 2024 and expires on June 2, 2024.

### Added
- The `PATCH /user` endpoint now includes an optional `access_code` parameter and returns a `403` response if given an invalid or inactive access code.

### Changed
- Turn off hyp3 ACCESS spend by zeroing the max VCPUs in the associated deployment.
- Reduce product lifetime in hyp3 ACCESS deployment to 14 days.

## [7.2.1]

### Fixed
Expand Down
8 changes: 8 additions & 0 deletions apps/api/api-cf.yml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ Parameters:
UsersTable:
Type: String

AccessCodesTable:
Type: String

AuthPublicKey:
Type: String

Expand Down Expand Up @@ -171,6 +174,10 @@ Resources:
- dynamodb:PutItem
- dynamodb:UpdateItem
Resource: !Sub "arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${UsersTable}*"
- Effect: Allow
Action:
- dynamodb:GetItem
Resource: !Sub "arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${AccessCodesTable}*"

Lambda:
Type: AWS::Lambda::Function
Expand All @@ -179,6 +186,7 @@ Resources:
Variables:
JOBS_TABLE_NAME: !Ref JobsTable
USERS_TABLE_NAME: !Ref UsersTable
ACCESS_CODES_TABLE_NAME: !Ref AccessCodesTable
AUTH_PUBLIC_KEY: !Ref AuthPublicKey
AUTH_ALGORITHM: !Ref AuthAlgorithm
DEFAULT_CREDITS_PER_USER: !Ref DefaultCreditsPerUser
Expand Down
7 changes: 7 additions & 0 deletions apps/api/src/hyp3_api/api-spec/openapi-spec.yml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ components:
properties:
use_case:
$ref: "#/components/schemas/use_case"
access_code:
$ref: "#/components/schemas/access_code"

user:
description: Information about a user
Expand Down Expand Up @@ -315,6 +317,11 @@ components:
type: string
example: I want to process data.

access_code:
description: Grants automatic user approval while the code remains active.
type: string
example: 123

user_id:
description: Username from Earthdata Login.
type: string
Expand Down
4 changes: 3 additions & 1 deletion apps/api/src/hyp3_api/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from flask import abort, jsonify, request

import dynamo
from dynamo.exceptions import InsufficientCreditsError, UnexpectedApplicationStatusError
from dynamo.exceptions import AccessCodeError, InsufficientCreditsError, UnexpectedApplicationStatusError
from hyp3_api import util
from hyp3_api.validation import GranuleValidationError, validate_jobs

Expand Down Expand Up @@ -65,6 +65,8 @@ def patch_user(body: dict, user: str, edl_access_token: str) -> dict:
print(body)
try:
user_record = dynamo.user.update_user(user, edl_access_token, body)
except AccessCodeError as e:
abort(problem_format(403, str(e)))
except UnexpectedApplicationStatusError as e:
abort(problem_format(403, str(e)))
return _user_response(user_record)
Expand Down
12 changes: 12 additions & 0 deletions apps/main-cf.yml.j2
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ Resources:
Parameters:
JobsTable: !Ref JobsTable
UsersTable: !Ref UsersTable
AccessCodesTable: !Ref AccessCodesTable
AuthPublicKey: !Ref AuthPublicKey
AuthAlgorithm: !Ref AuthAlgorithm
DefaultCreditsPerUser: !Ref DefaultCreditsPerUser
Expand Down Expand Up @@ -356,6 +357,17 @@ Resources:
- AttributeName: user_id
KeyType: HASH

AccessCodesTable:
Type: AWS::DynamoDB::Table
Properties:
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: access_code
AttributeType: S
KeySchema:
- AttributeName: access_code
KeyType: HASH

{% if security_environment == 'EDC' %}
DisablePrivateDNS:
Type: AWS::CloudFormation::Stack
Expand Down
4 changes: 4 additions & 0 deletions lib/dynamo/dynamo/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ class DatabaseConditionException(Exception):
"""Raised when a DynamoDB condition expression check fails."""


class AccessCodeError(Exception):
"""Raised when a user application includes an invalid or expired access code."""


class InsufficientCreditsError(Exception):
"""Raised when trying to submit jobs whose total cost exceeds the user's remaining credits."""

Expand Down
5 changes: 2 additions & 3 deletions lib/dynamo/dynamo/jobs.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import json
from datetime import datetime, timezone
from decimal import Decimal
from os import environ
from pathlib import Path
Expand All @@ -17,7 +16,7 @@
RejectedApplicationError,
)
from dynamo.user import APPLICATION_APPROVED, APPLICATION_NOT_STARTED, APPLICATION_PENDING, APPLICATION_REJECTED
from dynamo.util import DYNAMODB_RESOURCE, convert_floats_to_decimals, format_time, get_request_time_expression
from dynamo.util import DYNAMODB_RESOURCE, convert_floats_to_decimals, current_utc_time, get_request_time_expression

costs_file = Path(__file__).parent / 'costs.json'
COSTS = convert_floats_to_decimals(json.loads(costs_file.read_text()))
Expand All @@ -32,7 +31,7 @@

def put_jobs(user_id: str, jobs: List[dict], dry_run=False) -> List[dict]:
table = DYNAMODB_RESOURCE.Table(environ['JOBS_TABLE_NAME'])
request_time = format_time(datetime.now(timezone.utc))
request_time = current_utc_time()

user_record = dynamo.user.get_or_create_user(user_id)

Expand Down
58 changes: 44 additions & 14 deletions lib/dynamo/dynamo/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@
import botocore.exceptions
import requests

import dynamo.util
from dynamo.exceptions import (
ApprovedApplicationError, DatabaseConditionException, InvalidApplicationStatusError, RejectedApplicationError
AccessCodeError,
ApprovedApplicationError,
DatabaseConditionException,
InvalidApplicationStatusError,
RejectedApplicationError,
)
from dynamo.util import DYNAMODB_RESOURCE

Expand All @@ -21,26 +26,44 @@ def update_user(user_id: str, edl_access_token: str, body: dict) -> dict:
user = get_or_create_user(user_id)
application_status = user['application_status']
if application_status in (APPLICATION_NOT_STARTED, APPLICATION_PENDING):
access_code = body.get('access_code')
if access_code:
_validate_access_code(access_code)
updated_application_status = APPLICATION_APPROVED
access_code_expression = ', access_code = :access_code'
access_code_value = {':access_code': access_code}
else:
updated_application_status = APPLICATION_PENDING
access_code_expression = ''
access_code_value = {}
edl_profile = _get_edl_profile(user_id, edl_access_token)
users_table = DYNAMODB_RESOURCE.Table(environ['USERS_TABLE_NAME'])
try:
user = users_table.update_item(
Key={'user_id': user_id},
UpdateExpression='SET #edl_profile = :edl_profile, use_case = :use_case, application_status = :pending',
UpdateExpression=(
'SET #edl_profile = :edl_profile,'
' use_case = :use_case,'
' application_status = :updated_application_status'
f'{access_code_expression}'
),
ConditionExpression='application_status IN (:not_started, :pending)',
ExpressionAttributeNames={'#edl_profile': '_edl_profile'},
ExpressionAttributeValues={
':edl_profile': edl_profile,
':use_case': body['use_case'],
':not_started': APPLICATION_NOT_STARTED,
':pending': APPLICATION_PENDING
':pending': APPLICATION_PENDING,
':updated_application_status': updated_application_status,
**access_code_value
},
ReturnValues='ALL_NEW',
)['Attributes']
except botocore.exceptions.ClientError as e:
if e.response['Error']['Code'] == 'ConditionalCheckFailedException':
raise DatabaseConditionException(f'Failed to update record for user {user_id}')
raise
user = _reset_credits_if_needed(user=user, current_month=_get_current_month(), users_table=users_table)
return user
if application_status == APPLICATION_REJECTED:
raise RejectedApplicationError(user_id)
Expand All @@ -49,6 +72,21 @@ def update_user(user_id: str, edl_access_token: str, body: dict) -> dict:
raise InvalidApplicationStatusError(user_id, application_status)


def _validate_access_code(access_code: str) -> None:
access_codes_table = DYNAMODB_RESOURCE.Table(environ['ACCESS_CODES_TABLE_NAME'])
item = access_codes_table.get_item(Key={'access_code': access_code}).get('Item')

if item is None:
raise AccessCodeError(f'{access_code} is not a valid access code')

now = dynamo.util.current_utc_time()
if now < item['start_date']:
raise AccessCodeError(f'Access code {access_code} will become active on {item["start_date"]}')

if now >= item['end_date']:
raise AccessCodeError(f'Access code {access_code} expired on {item["end_date"]}')


def _get_edl_profile(user_id: str, edl_access_token: str) -> dict:
url = f'https://urs.earthdata.nasa.gov/api/users/{user_id}'
response = requests.get(url, headers={'Authorization': f'Bearer {edl_access_token}'})
Expand All @@ -57,21 +95,13 @@ def _get_edl_profile(user_id: str, edl_access_token: str) -> dict:


def get_or_create_user(user_id: str) -> dict:
current_month = _get_current_month()
default_credits = Decimal(os.environ['DEFAULT_CREDITS_PER_USER'])

users_table = DYNAMODB_RESOURCE.Table(environ['USERS_TABLE_NAME'])
user = users_table.get_item(Key={'user_id': user_id}).get('Item')

if user is None:
user = _create_user(user_id, users_table)

return _reset_credits_if_needed(
user=user,
default_credits=default_credits,
current_month=current_month,
users_table=users_table,
)
return _reset_credits_if_needed(user=user, current_month=_get_current_month(), users_table=users_table)


def _get_current_month() -> str:
Expand All @@ -93,7 +123,7 @@ def _create_user(user_id: str, users_table) -> dict:
return user


def _reset_credits_if_needed(user: dict, default_credits: Decimal, current_month: str, users_table) -> dict:
def _reset_credits_if_needed(user: dict, current_month: str, users_table) -> dict:
if (
user['application_status'] == APPLICATION_APPROVED
and user.get('_month_of_last_credit_reset', '0') < current_month # noqa: W503
Expand All @@ -112,7 +142,7 @@ def _reset_credits_if_needed(user: dict, default_credits: Decimal, current_month
ExpressionAttributeNames={'#month_of_last_credit_reset': '_month_of_last_credit_reset'},
ExpressionAttributeValues={
':approved': APPLICATION_APPROVED,
':credits': user.get('credits_per_month', default_credits),
':credits': user.get('credits_per_month', Decimal(os.environ['DEFAULT_CREDITS_PER_USER'])),
':current_month': current_month,
':number': 'N',
},
Expand Down
Loading
Loading