diff --git a/docs/How-We-Work/Team-Composition.md b/docs/How-We-Work/Team-Composition.md
index e75776003..65a984d97 100644
--- a/docs/How-We-Work/Team-Composition.md
+++ b/docs/How-We-Work/Team-Composition.md
@@ -8,14 +8,13 @@ Please refer to the [Team Members doc](https://hhsgov.sharepoint.com/:w:/r/sites
* Alexandra Pennington, OFA, tech lead
**Raft**
-* Connor Smith, Raft, facilitator/product manager
-* Miles Reiter, Raft, design lead + senior ux/ui researcher and designer
-* Diana Liang, Raft, ux/ui researcher and designer
+* Rob Gendron, Raft, facilitator/product manager
+* Victoria Amoroso, Raft, design lead + senior ux/ui researcher and designer
+* Miles Reiter, Raft, senior ux/ui researcher and designer
* Andrew Jameson, Raft, tech lead
-* Cameron Smart, Raft, full stack engineer
* Jan Timpe, Raft, full stack engineer
* Mo Sohani, Raft, full stack engineer
-* George Hudson, Raft, devops engineer
+* Eric Lipe, Raft, full stack engineer
## Subject Matter Experts
**OFA Data Team**
diff --git a/docs/Security-Compliance/File-Transfer-TDRS/README.md b/docs/Security-Compliance/File-Transfer-TDRS/README.md
deleted file mode 100644
index 0333257be..000000000
--- a/docs/Security-Compliance/File-Transfer-TDRS/README.md
+++ /dev/null
@@ -1,26 +0,0 @@
-# Boundary diagram with file transfer from TDP to TDRS
-
-
-The [TDP boundary diagram](../boundary-diagram.md) has been _temporarily_ modified herein to reflect updates to the data flow.
-
-
-
-
-### Updated Data flow
-
-Data files from grantees will, for the most part, follow the original flow:
-- users with `OFA Admin` and (STT) `Data Analyst` roles will upload and submit files via the web application
-- upon submission, files will be scanned for viruses via ClamAV. Infected files will be discarded, and clean files will be stored in cloud.gov AWS S3 buckets.
-
-#### _What's new?_
-Files stored in cloud.gov's encrypted AWS S3 buckets will be transferred via SFTP to the ACFTitan server, which lives within the legacy system's (TDRS) ATO boundary diagram, as shown below. A more complete visual of the TDRS architecture and ATO boundary can be found [here](https://hhsgov.sharepoint.com/sites/TANFDataPortalOFA-TestPrivateChannel/Shared%20Documents/Forms/AllItems.aspx?id=%2Fsites%2FTANFDataPortalOFA%2DTestPrivateChannel%2FShared%20Documents%2FTest%20Private%20Channel%2FExamples%2FTDRS%2FBoundary%20Diagram%2FTANF%20Network%20Diagram%2EJPG&parent=%2Fsites%2FTANFDataPortalOFA%2DTestPrivateChannel%2FShared%20Documents%2FTest%20Private%20Channel%2FExamples%2FTDRS%2FBoundary%20Diagram) :lock:.
-
-These files will be picked up by the ACF OCIO Ops team, who maintain TDRS, for data processing and dB storage. This transfer process is temporary until TDP reaches parity with TDRS in terms of data processing, validation, and dB storage. More background on TDRS functionality can be found [here](../../Background/Current-TDRS.md)
-
-![Boundary diagram](diagram.png)
-
-## Updating
-
-- Download latest version pdf diagram [draw.io](diagram.drawio)
-- Edit this diagram with [draw.io](https://app.diagrams.net/)
-- Update the image and point download link to correct file
diff --git a/docs/Security-Compliance/File-Transfer-TDRS/diagram.drawio b/docs/Security-Compliance/File-Transfer-TDRS/diagram.drawio
deleted file mode 100644
index 2c22f92dd..000000000
--- a/docs/Security-Compliance/File-Transfer-TDRS/diagram.drawio
+++ /dev/null
@@ -1 +0,0 @@
-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
\ No newline at end of file
diff --git a/docs/Security-Compliance/File-Transfer-TDRS/diagram.png b/docs/Security-Compliance/File-Transfer-TDRS/diagram.png
deleted file mode 100644
index 476b82d33..000000000
Binary files a/docs/Security-Compliance/File-Transfer-TDRS/diagram.png and /dev/null differ
diff --git a/docs/Technical-Documentation/secret-key-rotation-steps.md b/docs/Technical-Documentation/secret-key-rotation-steps.md
index bb10ad880..b6f58c39e 100644
--- a/docs/Technical-Documentation/secret-key-rotation-steps.md
+++ b/docs/Technical-Documentation/secret-key-rotation-steps.md
@@ -6,7 +6,6 @@ To maintain good security, we will periodically rotate the following secret keys
- CF deployer keys (_for continuous delivery_)
- JWT keys (_external user auth_)
- ACF AMS keys (_internal user auth_)
-- ACF Titan server keys (_for file transfers between TDP and TDRS_)
- Django secret keys ([_cryptographic signing_](https://docs.djangoproject.com/en/4.0/topics/signing/#module-django.core.signing))
This document outlines the process for doing this for each set of keys.
@@ -154,61 +153,6 @@ Service requests tickets must be submitted by Government-authorized personnel wi
2. Update environment variables in CircleCI and relevant cloud.gov backend applications after ticket completed by OCIO. [Restage applications](https://cloud.gov/docs/deployment/app-maintenance/#restaging-your-app).
-**ACF Titan Server Keys
**
-The ACF OCIO Ops team manages these credentials for all environments (dev, staging, and prod), so we will need to submit a service request ticket whenever we need keys rotated.
-
-Service requests tickets must be submitted by Government-authorized personnel with Government computers and PIV access (e.g. Raft tech lead for lower environments and TDP sys admins for production environment). Please follow the procedures below:
-
-1. Generate new public/private key pair
-
-Below is an example of how to generate new titan public/private key pair from _Git BASH for Windows_. Two files called `filename_where_newtitan_keypair_saved` are created: one is the _private_ key and the other is a _public_ key (the latter is saved with a _.pub_ extention).
-(note: the info below is not associated with any real keys)
-
-```
-$ ssh-keygen -t rsa -b 4096
-Generating public/private rsa key pair.
-
-Enter file in which to save the key (/c/Users/username/.ssh/id_rsa): filename_where_newtitan_keypair_saved
-
-Enter passphrase (empty for no passphrase):
-
-Enter same passphrase again:
-
-Your identification has been saved in filename_where_newtitan_keypair_saved
-
-Your public key has been saved in filename_where_newtitan_keypair_saved.pub
-
-The key fingerprint is:
-SHA256:BY6Nl0hCjIrI9yZMBGH2vbDFLCTq2DsFQXQTmLydwjI
-
-The key's randomart image is:
-+---[RSA 4096]----+
-| X*B*.. . |
-|+ O+=+ * o |
-|=oo* *+ = . |
-|Eo++B .. . |
-|.+=oo. S |
-| = o |
-| o o |
-| . |
-| |
-+----[SHA256]-----+
-```
-
-2. Submit request tickets from government-issued email address and use the email template located on **page 2** of [this document.](https://hhsgov.sharepoint.com/:w:/r/sites/TANFDataPortalOFA/Shared%20Documents/compliance/Authentication%20%26%20Authorization/ACF%20AMS%20docs/OCIO%20OPERATIONS%20REQUEST%20TEMPLATES.docx?d=w5332585c1ecf49a4aeda17674f687154&csf=1&web=1&e=aQyIPz) cc OFA tech lead on lower environment requests.
-
-The request should include:
-- the titan service account name (i.e. `tanfdp` for prod; `tanfdpdev` for dev/staging)
-- the newly generated public key from `filename_where_newtitan_keypair_saved.pub`
-
-3. When OCIO confirms that the change has been made, add the private key from `filename_where_newtitan_keypair_saved` to CircleCI as an environment variable. The variable name is `ACFTITAN_KEY`. **Please note**: the value needs must be edited before adding to CircleCI. It should be a one-line string with underscores ("_") replacing the spaces at the end of every line. See example below:
-
-```
------BEGIN OPENSSH PRIVATE KEY-----_somehashvalue_-----END OPENSSH PRIVATE KEY-----
-```
-
-4. Re-run the deployment workflow from CircleCI and confirm that the updated key value pair has been added to the relevant cloud.gov backend application.
-
**Django secret keys
**
diff --git a/scripts/deploy-backend.sh b/scripts/deploy-backend.sh
index 3f53b6b59..24bef90d9 100755
--- a/scripts/deploy-backend.sh
+++ b/scripts/deploy-backend.sh
@@ -42,9 +42,6 @@ echo backend_app_name: "$backend_app_name"
set_cf_envs()
{
var_list=(
- "ACFTITAN_HOST"
- "ACFTITAN_KEY"
- "ACFTITAN_USERNAME"
"AMS_CLIENT_ID"
"AMS_CLIENT_SECRET"
"AMS_CONFIGURATION_ENDPOINT"
diff --git a/tdrs-backend/.env.example b/tdrs-backend/.env.example
index af513c929..5ffe271c1 100644
--- a/tdrs-backend/.env.example
+++ b/tdrs-backend/.env.example
@@ -86,6 +86,3 @@ ELASTIC_HOST=elastic:9200
# testing
CYPRESS_TOKEN=local-cypress-token
-
-# sftp
-ACFTITAN_SFTP_PYTEST=local-acftitan-key
diff --git a/tdrs-backend/Pipfile b/tdrs-backend/Pipfile
index 7ab59800e..117e86c75 100644
--- a/tdrs-backend/Pipfile
+++ b/tdrs-backend/Pipfile
@@ -51,8 +51,6 @@ celery = "==5.2.6"
redis = "==4.1.2"
flower = "==1.1.0"
django-celery-beat = "==2.2.1"
-paramiko = "==2.11.0"
-pytest_sftpserver = "==1.3.0"
elasticsearch = "==7.13.4" # REQUIRED - v7.14.0 introduces breaking changes
django-elasticsearch-dsl = "==7.3"
django-elasticsearch-dsl-drf = "==0.22.5"
diff --git a/tdrs-backend/Pipfile.lock b/tdrs-backend/Pipfile.lock
index d62cb708b..c2cdbfdc0 100644
--- a/tdrs-backend/Pipfile.lock
+++ b/tdrs-backend/Pipfile.lock
@@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
- "sha256": "e0b5d173936dd0ae24d434e543a96d139eed6ab962f1f92b1fe354d74d9a0599"
+ "sha256": "a082fb8d3118128843dec21e83b70a4ee5d9743a2e869918452d1b8c47533edc"
},
"pipfile-spec": 6,
"requires": {
@@ -39,39 +39,6 @@
],
"version": "==2.4.1"
},
- "bcrypt": {
- "hashes": [
- "sha256:01746eb2c4299dd0ae1670234bf77704f581dd72cc180f444bfe74eb80495b64",
- "sha256:037c5bf7c196a63dcce75545c8874610c600809d5d82c305dd327cd4969995bf",
- "sha256:094fd31e08c2b102a14880ee5b3d09913ecf334cd604af27e1013c76831f7b05",
- "sha256:0d4cf6ef1525f79255ef048b3489602868c47aea61f375377f0d00514fe4a78c",
- "sha256:193bb49eeeb9c1e2db9ba65d09dc6384edd5608d9d672b4125e9320af9153a15",
- "sha256:2505b54afb074627111b5a8dc9b6ae69d0f01fea65c2fcaea403448c503d3991",
- "sha256:2ee15dd749f5952fe3f0430d0ff6b74082e159c50332a1413d51b5689cf06623",
- "sha256:31adb9cbb8737a581a843e13df22ffb7c84638342de3708a98d5c986770f2834",
- "sha256:3a5be252fef513363fe281bafc596c31b552cf81d04c5085bc5dac29670faa08",
- "sha256:3d3b317050a9a711a5c7214bf04e28333cf528e0ed0ec9a4e55ba628d0f07c1a",
- "sha256:48429c83292b57bf4af6ab75809f8f4daf52aa5d480632e53707805cc1ce9b74",
- "sha256:4a8bea4c152b91fd8319fef4c6a790da5c07840421c2b785084989bf8bbb7455",
- "sha256:4fb253d65da30d9269e0a6f4b0de32bd657a0208a6f4e43d3e645774fb5457f3",
- "sha256:551b320396e1d05e49cc18dd77d970accd52b322441628aca04801bbd1d52a73",
- "sha256:5f7cd3399fbc4ec290378b541b0cf3d4398e4737a65d0f938c7c0f9d5e686611",
- "sha256:6004f5229b50f8493c49232b8e75726b568535fd300e5039e255d919fc3a07f2",
- "sha256:6717543d2c110a155e6821ce5670c1f512f602eabb77dba95717ca76af79867d",
- "sha256:6cac78a8d42f9d120b3987f82252bdbeb7e6e900a5e1ba37f6be6fe4e3848286",
- "sha256:8a893d192dfb7c8e883c4576813bf18bb9d59e2cfd88b68b725990f033f1b978",
- "sha256:8cbb119267068c2581ae38790e0d1fbae65d0725247a930fc9900c285d95725d",
- "sha256:9f8ea645eb94fb6e7bea0cf4ba121c07a3a182ac52876493870033141aa687bc",
- "sha256:c4c8d9b3e97209dd7111bf726e79f638ad9224b4691d1c7cfefa571a09b1b2d6",
- "sha256:cb9c707c10bddaf9e5ba7cdb769f3e889e60b7d4fea22834b261f51ca2b89fed",
- "sha256:d84702adb8f2798d813b17d8187d27076cca3cd52fe3686bb07a9083930ce650",
- "sha256:ec3c2e1ca3e5c4b9edb94290b356d082b721f3f50758bce7cce11d8a7c89ce84",
- "sha256:f44a97780677e7ac0ca393bd7982b19dbbd8d7228c1afe10b128fd9550eef5f1",
- "sha256:f5698ce5292a4e4b9e5861f7e53b1d89242ad39d54c3da451a93cac17b61921a"
- ],
- "markers": "python_version >= '3.7'",
- "version": "==4.1.3"
- },
"billiard": {
"hashes": [
"sha256:299de5a8da28a783d51b197d496bef4f1595dd023a93a4f59dde1886ae905547",
@@ -694,14 +661,6 @@
"markers": "python_version >= '3.7'",
"version": "==24.0"
},
- "paramiko": {
- "hashes": [
- "sha256:003e6bee7c034c21fbb051bf83dc0a9ee4106204dd3c53054c71452cc4ec3938",
- "sha256:655f25dc8baf763277b933dfcea101d636581df8d6b9774d1fb653426b72c270"
- ],
- "index": "pypi",
- "version": "==2.11.0"
- },
"parso": {
"hashes": [
"sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18",
@@ -868,36 +827,11 @@
"markers": "python_version >= '3.6'",
"version": "==2.4.0"
},
- "pynacl": {
- "hashes": [
- "sha256:06b8f6fa7f5de8d5d2f7573fe8c863c051225a27b61e6860fd047b1775807858",
- "sha256:0c84947a22519e013607c9be43706dd42513f9e6ae5d39d3613ca1e142fba44d",
- "sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93",
- "sha256:401002a4aaa07c9414132aaed7f6836ff98f59277a234704ff66878c2ee4a0d1",
- "sha256:52cb72a79269189d4e0dc537556f4740f7f0a9ec41c1322598799b0bdad4ef92",
- "sha256:61f642bf2378713e2c2e1de73444a3778e5f0a38be6fee0fe532fe30060282ff",
- "sha256:8ac7448f09ab85811607bdd21ec2464495ac8b7c66d146bf545b0f08fb9220ba",
- "sha256:a36d4a9dda1f19ce6e03c9a784a2921a4b726b02e1c736600ca9c22029474394",
- "sha256:a422368fc821589c228f4c49438a368831cb5bbc0eab5ebe1d7fac9dded6567b",
- "sha256:e46dae94e34b085175f8abb3b0aaa7da40767865ac82c928eeb9e57e1ea8a543"
- ],
- "markers": "python_version >= '3.6'",
- "version": "==1.5.0"
- },
- "pytest-sftpserver": {
- "hashes": [
- "sha256:b7ac34a23f63d77e27f67b6a81c9418243733f027eeb8a3061d965b2da7e5cab",
- "sha256:c5e8a37049866d4eabc711db9f1c09e1c02ab72ba290f5fd244939c9a188042f"
- ],
- "index": "pypi",
- "version": "==1.3.0"
- },
"python-crontab": {
"hashes": [
- "sha256:6d5ba3c190ec76e4d252989a1644fcb233dbf53fbc8fceeb9febe1657b9fb1d4",
- "sha256:79fb7465039ddfd4fb93d072d6ee0d45c1ac8bf1597f0686ea14fd4361dba379"
+ "sha256:f4ea1605d24533b67fa7a634ef26cb59a5f2e7954f6e677d2d7a2229959a2fc8"
],
- "version": "==3.0.0"
+ "version": "==3.1.0"
},
"python-dateutil": {
"hashes": [
@@ -1040,11 +974,11 @@
},
"setuptools": {
"hashes": [
- "sha256:6c1fccdac05a97e598fb0ae3bbed5904ccb317337a51139dcd51453611bbb987",
- "sha256:c636ac361bc47580504644275c9ad802c50415c7522212252c033bd15f301f32"
+ "sha256:54faa7f2e8d2d11bcd2c07bed282eef1046b5c080d1c32add737d7b5817b1ad4",
+ "sha256:f211a66637b8fa059bb28183da127d4e86396c991a942b028c6650d4319c3fd0"
],
"markers": "python_version >= '3.8'",
- "version": "==69.5.1"
+ "version": "==70.0.0"
},
"six": {
"hashes": [
@@ -1381,11 +1315,11 @@
},
"faker": {
"hashes": [
- "sha256:6737cc6d591cd83421fdc5e494f6e2c1a6e32266214f158b745aa9fa15687c98",
- "sha256:c153505618801f1704807b258a6010ea8cabf91f66f4788939bfdba83b887e76"
+ "sha256:45b84f47ff1ef86e3d1a8d11583ca871ecf6730fad0660edadc02576583a2423",
+ "sha256:cfe97c4857c4c36ee32ea4aaabef884895992e209bae4cbd26807cf3e05c6918"
],
"markers": "python_version >= '3.8'",
- "version": "==25.0.1"
+ "version": "==25.2.0"
},
"flake8": {
"hashes": [
diff --git a/tdrs-backend/docker-compose.local.yml b/tdrs-backend/docker-compose.local.yml
index d2cd5289c..2de355c9c 100644
--- a/tdrs-backend/docker-compose.local.yml
+++ b/tdrs-backend/docker-compose.local.yml
@@ -68,12 +68,8 @@ services:
- AMS_CLIENT_ID
- AMS_CLIENT_SECRET
- AMS_CONFIGURATION_ENDPOINT
- - ACFTITAN_HOST
- - ACFTITAN_KEY
- - ACFTITAN_USERNAME
- REDIS_URI=redis://redis-server:6379
- REDIS_SERVER_LOCAL=TRUE
- - ACFTITAN_SFTP_PYTEST
- SENDGRID_API_KEY
volumes:
- .:/tdpapp
diff --git a/tdrs-backend/docker-compose.yml b/tdrs-backend/docker-compose.yml
index dba1be5de..07d014fb5 100644
--- a/tdrs-backend/docker-compose.yml
+++ b/tdrs-backend/docker-compose.yml
@@ -91,12 +91,8 @@ services:
- AMS_CLIENT_ID
- AMS_CLIENT_SECRET
- AMS_CONFIGURATION_ENDPOINT
- - ACFTITAN_HOST
- - ACFTITAN_KEY
- - ACFTITAN_USERNAME
- REDIS_URI=redis://redis-server:6379
- REDIS_SERVER_LOCAL=TRUE
- - ACFTITAN_SFTP_PYTEST
- CYPRESS_TOKEN
- DJANGO_DEBUG
- SENDGRID_API_KEY
diff --git a/tdrs-backend/tdpservice/data_files/views.py b/tdrs-backend/tdpservice/data_files/views.py
index dfcc71416..3f67d7cb3 100644
--- a/tdrs-backend/tdpservice/data_files/views.py
+++ b/tdrs-backend/tdpservice/data_files/views.py
@@ -18,7 +18,7 @@
from tdpservice.data_files.util import get_xls_serialized_file
from tdpservice.data_files.models import DataFile, get_s3_upload_path
from tdpservice.users.permissions import DataFilePermissions, IsApprovedPermission
-from tdpservice.scheduling import sftp_task, parser_task
+from tdpservice.scheduling import parser_task
from tdpservice.data_files.s3_client import S3Client
from tdpservice.parsers.models import ParserError
from tdpservice.parsers.serializers import ParsingErrorSerializer
@@ -59,7 +59,6 @@ def create(self, request, *args, **kwargs):
# only if file is passed the virus scan and created successfully will we perform side-effects:
# * Send to parsing
- # * Upload to ACF-TITAN
# * Send email to user
logger.debug(f"{self.__class__.__name__}: status: {response.status_code}")
@@ -74,15 +73,6 @@ def create(self, request, *args, **kwargs):
parser_task.parse.delay(data_file_id)
logger.info("Submitted parse task to queue for datafile %s.", data_file_id)
- sftp_task.upload.delay(
- data_file_pk=data_file_id,
- server_address=settings.ACFTITAN_SERVER_ADDRESS,
- local_key=settings.ACFTITAN_LOCAL_KEY,
- username=settings.ACFTITAN_USERNAME,
- port=22
- )
- logger.info("Submitted upload task to redis for datafile %s.", data_file_id)
-
app_name = settings.APP_NAME + '/'
key = app_name + get_s3_upload_path(data_file, '')
version_id = self.get_s3_versioning_id(response.data.get('original_filename'), key)
diff --git a/tdrs-backend/tdpservice/scheduling/sftp_task.py b/tdrs-backend/tdpservice/scheduling/sftp_task.py
deleted file mode 100644
index d4807ac88..000000000
--- a/tdrs-backend/tdpservice/scheduling/sftp_task.py
+++ /dev/null
@@ -1,135 +0,0 @@
-"""schedule tasks."""
-
-from __future__ import absolute_import
-
-# The tasks
-
-import hashlib
-import os
-
-from celery import shared_task
-from django.conf import settings
-import datetime
-import paramiko
-import logging
-from tdpservice.data_files.models import DataFile, LegacyFileTransfer
-
-logger = logging.getLogger(__name__)
-
-
-@shared_task(acks_late=True, worker_prefetch_multiplier=1)
-def upload(
- data_file_pk,
- server_address=settings.ACFTITAN_SERVER_ADDRESS,
- local_key=settings.ACFTITAN_LOCAL_KEY,
- username=settings.ACFTITAN_USERNAME,
- port=22,
-):
- """
- Upload to SFTP server.
-
- This task uploads the file in DataFile object with pk = data_file_pk
- to sftp server as defined in Settings file
- """
- # Upload file
- data_file = DataFile.objects.get(id=data_file_pk)
- file_transfer_record = LegacyFileTransfer(
- data_file=data_file,
- uploaded_by=data_file.user,
- file_name=data_file.filename if data_file.filename is not None else "None",
- )
-
- def write_key_to_file(private_key):
- """Paramiko require the key in file object format."""
- with open("temp_key_file", "w") as f:
- f.write(private_key)
- f.close()
- return "temp_key_file"
-
- def create_dir(directory_name, sftp_server):
- """Code snippet to create directory in SFTP server."""
- try:
- sftp_server.chdir(directory_name) # Test if remote_path exists
- except IOError:
- sftp_server.mkdir(directory_name) # Create remote_path
- sftp_server.chdir(directory_name)
-
- for attempt in range(1, 4):
- logger.info("Attempt {} to upload file {}".format(attempt, data_file.filename))
- try:
- # Create directory names for ACF titan
- destination = str(data_file.filename)
- today_date = datetime.datetime.today()
- upper_directory_name = today_date.strftime("%Y%m%d")
- lower_directory_name = today_date.strftime(
- str(data_file.year) + "-" + str(data_file.quarter)
- )
-
- # Paramiko need local file
- paramiko_local_file = data_file.file.read()
- with open(destination, "wb") as f1:
- f1.write(paramiko_local_file)
- file_transfer_record.file_size = f1.tell()
- file_transfer_record.file_shasum = hashlib.sha256(
- paramiko_local_file
- ).hexdigest()
- f1.close()
-
- # Paramiko SSH connection requires private key as file
- temp_key_file = write_key_to_file(local_key)
- os.chmod(temp_key_file, 0o600)
-
- # Create SFTP/SSH connection
- transport = paramiko.SSHClient()
- transport.set_missing_host_key_policy(paramiko.AutoAddPolicy())
- pkey = paramiko.RSAKey.from_private_key_file(temp_key_file)
- transport.connect(
- server_address,
- pkey=pkey,
- username=username,
- port=port,
- look_for_keys=False,
- banner_timeout=30,
- disabled_algorithms={"pubkeys": ["rsa-sha2-512", "rsa-sha2-256"]},
- )
- # remove temp key file
- os.remove(temp_key_file)
- sftp = transport.open_sftp()
-
- # Create remote directory
- create_dir(settings.ACFTITAN_DIRECTORY, sftp_server=sftp)
- create_dir(upper_directory_name, sftp_server=sftp)
- create_dir(lower_directory_name, sftp_server=sftp)
-
- # Put the file in SFTP server
- sftp.put(destination, destination)
-
- # Delete temp file
- os.remove(destination)
- logger.info(
- "File {} has been successfully uploaded to {}".format(
- destination, server_address
- )
- )
-
- # Add the log LegacyFileTransfer
- file_transfer_record.result = LegacyFileTransfer.Result.COMPLETED
- file_transfer_record.save()
- transport.close()
- return True
-
- except Exception as e:
- logger.error(
- "Attempt {} failed to upload {} with error:{}".format(
- attempt, destination, e
- )
- )
- transport.close()
- else:
- # All attempts failed
- logger.error("Failed to upload {} after 3 attempts".format(destination))
- file_transfer_record.file_size = 0
- file_transfer_record.result = LegacyFileTransfer.Result.ERROR
- file_transfer_record.save()
- transport.close()
- return False
diff --git a/tdrs-backend/tdpservice/scheduling/test/test_file_upload.py b/tdrs-backend/tdpservice/scheduling/test/test_file_upload.py
deleted file mode 100644
index 140ec6d64..000000000
--- a/tdrs-backend/tdpservice/scheduling/test/test_file_upload.py
+++ /dev/null
@@ -1,91 +0,0 @@
-"""Scheduling tests."""
-
-from datetime import datetime
-
-import pytest
-from paramiko import Transport
-from paramiko.sftp_client import SFTPClient
-from tdpservice.scheduling.sftp_task import upload
-from tdpservice.data_files.test.factories import DataFileFactory
-from tdpservice.stts.models import STT
-from django.conf import settings
-
-"""
-To mock sftp server, pytest_sftpserver (https://github.com/ulope/pytest-sftpserver) is used.
-The package provides two main fixtures for testing: sftpserver and sftpclient.
-"""
-
-@pytest.fixture
-def stt_instance(region):
- """Return an STT."""
- stt, _ = STT.objects.get_or_create(
- name="first",
- region=region,
- postal_code="AR",
- stt_code='234',
- filenames={
- 'Aggregate Data': 'ADS.E2J.NDM3.TS22',
- 'Active Case Data': 'test',
- 'Closed Case Data': 'ADS.E2J.NDM2.TS22'}
- )
- return stt
-
-@pytest.fixture
-def data_file_instance(stt_instance):
- """Prepare data file fixture instance for testing datafile."""
- return DataFileFactory.create(
- created_at=datetime.now(),
- stt=stt_instance
- )
-
-
-@pytest.fixture
-def sftp_connection_values(sftpserver):
- """SFTP connection values for local sftp server."""
- server_address = sftpserver.host
- local_key = settings.ACFTITAN_SFTP_PYTEST
- username = "user"
- port = sftpserver.port
- return {
- 'server_address': server_address,
- 'username': username,
- 'local_key': local_key,
- 'port': port
- }
-
-
-@pytest.fixture(scope="session")
-def sftpclient(sftpserver):
- """SFTP client for local sftp server."""
- transport = Transport((sftpserver.host, sftpserver.port))
- transport.connect(username="a", password="b")
- sftpclient = SFTPClient.from_transport(transport)
- yield sftpclient
- sftpclient.close()
- transport.close()
-
-
-@pytest.mark.django_db
-def test_new_data_file(sftpserver, data_file_instance, sftp_connection_values, sftpclient):
- """Datafile object for testing the file."""
- data_file_instance.save()
-
- """
- Need .serve_content to keep the communication alive
- Here we put a dummy file somefile.txt in a_dir to keep the port open
- """
- with sftpserver.serve_content({'a_dir': {'somefile.txt': "File content"}}):
- upload(data_file_instance.pk,
- server_address=sftp_connection_values['server_address'],
- local_key=sftp_connection_values['local_key'],
- username=sftp_connection_values['username'],
- port=sftp_connection_values['port'])
-
- # Create directory structure as needed for ACF_TITAN to assert correct directory name
- today_date = datetime.today()
- upper_directory_name = today_date.strftime('%Y%m%d')
- lower_directory_name = today_date.strftime(str(data_file_instance.year) +
- '-' +
- str(data_file_instance.quarter))
- assert sftpclient.listdir(upper_directory_name+'/'+lower_directory_name)[0] == \
- data_file_instance.filename
diff --git a/tdrs-backend/tdpservice/settings/common.py b/tdrs-backend/tdpservice/settings/common.py
index 6ca924fe0..d4f6e0c13 100644
--- a/tdrs-backend/tdpservice/settings/common.py
+++ b/tdrs-backend/tdpservice/settings/common.py
@@ -443,17 +443,6 @@ class Common(Configuration):
''
)
- # ------- SFTP CONFIG
- ACFTITAN_SERVER_ADDRESS = os.getenv('ACFTITAN_HOST', '')
- """
- To be able to fit the PRIVATE KEY in one line as environment variable, we replace the EOL
- with an underscore char.
- The next line replaces the _ with EOL before using the PRIVATE KEY
- """
- ACFTITAN_LOCAL_KEY = os.getenv('ACFTITAN_KEY', '').replace('_', '\n')
- ACFTITAN_USERNAME = os.getenv('ACFTITAN_USERNAME', '')
- ACFTITAN_DIRECTORY = os.getenv('ACFTITAN_DIRECTORY', '')
-
# -------- CELERY CONFIG
REDIS_URI = os.getenv(
'REDIS_URI',
diff --git a/tdrs-backend/tdpservice/settings/local.py b/tdrs-backend/tdpservice/settings/local.py
index ae22cbcab..171608fe5 100644
--- a/tdrs-backend/tdpservice/settings/local.py
+++ b/tdrs-backend/tdpservice/settings/local.py
@@ -43,12 +43,3 @@ class Local(Common):
}
REDIS_SERVER_LOCAL = bool(strtobool(os.getenv("REDIS_SERVER_LOCAL", "TRUE")))
-
- # SFTP TEST KEY
- """
- To be able to fit the PRIVATE KEY in one line as environment variable, we replace the EOL
- with an underscore char.
- The next line replaces the _ with EOL before using the PRIVATE KEY
- """
- ACFTITAN_SFTP_PYTEST = os.getenv("ACFTITAN_SFTP_PYTEST").replace('_', '\n')
- APP_NAME = "tdrs-backend-local"
diff --git a/tdrs-frontend/nginx/cloud.gov/ip_whitelist_ipv6.conf b/tdrs-frontend/nginx/cloud.gov/ip_whitelist_ipv6.conf
index ba40f179c..ef268bef8 100644
--- a/tdrs-frontend/nginx/cloud.gov/ip_whitelist_ipv6.conf
+++ b/tdrs-frontend/nginx/cloud.gov/ip_whitelist_ipv6.conf
@@ -517677,6 +517677,7 @@ allow 2606:A000:EFC0:6B:3DBD:F080::/90;
allow 2606:A000:EFC0:6B:3DBD:F0C0::/91;
allow 2606:A000:EFC0:6B:3DBD:F0E0::/93;
allow 2606:A000:EFC0:6B:3DBD:F0E8::/98;
+allow 2607:fb90::/31;
allow 2610:A1:3068:252:0:4::/94;
allow 2610:A1:3068:252:0:8::/93;
allow 2610:A1:3068:252:0:10::/92;