diff --git a/lando/worker/cwlworkflow.py b/lando/worker/cwlworkflow.py
index d54b2f5..a81f3f8 100644
--- a/lando/worker/cwlworkflow.py
+++ b/lando/worker/cwlworkflow.py
@@ -97,8 +97,10 @@ class CwlWorkflowDownloader(object):
         self.workflow_url = workflow_url
         self.workflow_path = workflow_path
         self.workflow_basename = os.path.basename(self.workflow_url)
-        self.workflow_to_run = None # set by handle_*_download
-        self.workflow_to_report = None
+        # below are set by handle_*_download
+        self.workflow_to_run = None # Absolute path of workflow in lando VM
+        self.workflow_to_report = None # Relative path to use in templated report (may include #main)
+        self.workflow_to_read = None # Relative path to use when parsing for workflow inputs
         self.download_path = os.path.join(self.working_directory, self.workflow_basename)
         urllib.request.urlretrieve(self.workflow_url, self.download_path)
         if self.workflow_type == self.TYPE_PACKED:
@@ -112,6 +114,7 @@ class CwlWorkflowDownloader(object):
         # After downloading packed workflow, just append the workflow path to the local file name
         self.workflow_to_run = self.download_path + self.workflow_path
         self.workflow_to_report = self.workflow_basename + self.workflow_path
+        self.workflow_to_read = self.workflow_basename
 
     def _unzip_to_directory(self, directory):
         with zipfile.ZipFile(self.download_path) as z:
@@ -122,6 +125,7 @@ class CwlWorkflowDownloader(object):
         self._unzip_to_directory(self.working_directory)
         self.workflow_to_run = os.path.join(self.working_directory, self.workflow_path)
         self.workflow_to_report = self.workflow_path
+        self.workflow_to_read = self.workflow_path
 
     def copy_to_directory(self, directory):
         """
@@ -389,7 +393,7 @@ class ResultsDirectory(object):
         """
         logs_directory = os.path.join(self.docs_directory, LOGS_DIRECTORY)
         workflow_directory = os.path.join(self.docs_directory, WORKFLOW_DIRECTORY)
-        workflow_info = create_workflow_info(workflow_path=os.path.join(workflow_directory, self.workflow_downloader.workflow_to_report))
+        workflow_info = create_workflow_info(workflow_path=os.path.join(workflow_directory, self.workflow_downloader.workflow_to_read))
         workflow_info.update_with_job_order(job_order_path=os.path.join(workflow_directory, self.job_order_filename))
         workflow_info.update_with_job_output(job_output_path=os.path.join(logs_directory, JOB_STDOUT_FILENAME))
         job_data = {

cwlreport uses badly formed path for packed workflows
Test job 70 with a packed workflow failed because `workflow_to_report` included `#main`

```
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/lando/worker/worker.py", line 186, in run
    self.func(working_directory, self.payload)
  File "/usr/local/lib/python3.5/dist-packages/lando/worker/worker.py", line 103, in run_workflow
    workflow.run(payload.workflow_type, payload.workflow_url, payload.workflow_path, payload.job_order)
  File "/usr/local/lib/python3.5/dist-packages/lando/worker/cwlworkflow.py", line 243, in run
    results_directory.add_files(process)
  File "/usr/local/lib/python3.5/dist-packages/lando/worker/cwlworkflow.py", line 359, in add_files
    self._create_report(cwl_process)
  File "/usr/local/lib/python3.5/dist-packages/lando/worker/cwlworkflow.py", line 392, in _create_report
    workflow_info = create_workflow_info(workflow_path=os.path.join(workflow_directory, self.workflow_downloader.workflow_to_report))
  File "/usr/local/lib/python3.5/dist-packages/lando/worker/cwlreport.py", line 114, in create_workflow_info
    doc = parse_yaml_or_json(workflow_path)
  File "/usr/local/lib/python3.5/dist-packages/lando/worker/cwlreport.py", line 313, in parse_yaml_or_json
    with codecs.open(path, mode='r', encoding='utf-8') as infile:
  File "/usr/lib/python3.5/codecs.py", line 895, in open
    file = builtins.open(filename, mode, buffering)
FileNotFoundError: [Errno 2] No such file or directory: 'data_for_job_70/working/results/docs/scripts/exomeseq.cwl#main'
```
diff --git a/lando/worker/tests/test_cwlworkflow.py b/lando/worker/tests/test_cwlworkflow.py
index 4b67f7c..0fa7fd0 100644
--- a/lando/worker/tests/test_cwlworkflow.py
+++ b/lando/worker/tests/test_cwlworkflow.py
@@ -352,9 +352,10 @@ class TestResultsDirectory(TestCase):
                        mock_save_data_to_directory, mock_create_dir_if_necessary):
         job_id = 1
         workflow_downloader = create_autospec(CwlWorkflowDownloader,
-                                              workflow_to_run='/tmp/nosuchpath.cwl',
-                                              workflow_to_report='nosuch.cwl',
-                                              workflow_basename='nosuch.cwl')
+                                              workflow_to_run='/tmp/nosuch-run.cwl',
+                                              workflow_to_report='nosuch-report.cwl',
+                                              workflow_basename='nosuch-base.cwl',
+                                              workflow_to_read='nosuch-read.cwl')
         cwl_directory = create_autospec(CwlDirectory,
                                         result_directory='/tmp/fakedir',
                                         job_order_file_path='/tmp/alsonotreal.json',
@@ -400,7 +401,7 @@ class TestResultsDirectory(TestCase):
             call(documentation_directory + 'scripts')
         ])
         mock_create_workflow_info.assert_has_calls([
-            call(workflow_path=(documentation_directory + 'scripts/nosuch.cwl')),
+            call(workflow_path=(documentation_directory + 'scripts/nosuch-read.cwl')),
             call().update_with_job_order(job_order_path=(documentation_directory + 'scripts/alsonotreal.json')),
             call().update_with_job_output(job_output_path=(documentation_directory + 'logs/cwltool-output.json')),
             call().count_output_files(),
@@ -417,9 +418,10 @@ class TestResultsDirectory(TestCase):
                                              mock_shutil, mock_save_data_to_directory, mock_create_dir_if_necessary):
         job_id = 1
         workflow_downloader = create_autospec(CwlWorkflowDownloader,
-                                              workflow_to_run='/tmp/nosuchpath.cwl',
-                                              workflow_to_report='nosuch.cwl',
-                                              workflow_basename='nosuch.cwl')
+                                              workflow_to_run='/tmp/nosuch.cwl#main',
+                                              workflow_to_report='nosuch-report.cwl',
+                                              workflow_basename='nosuch-base.cwl',
+                                              workflow_to_read='nosuch-read.cwl')
         cwl_directory = create_autospec(CwlDirectory,
                                         result_directory='/tmp/fakedir',
                                         job_order_file_path='/tmp/alsonotreal.json',

pip install -e .
parse_log_pytest
pytest
nose==1.3.7 pytest
3.6
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
adal==1.2.7
appdirs==1.4.4
attrs @ file:///opt/conda/conda-bld/attrs_1642510447205/work
cachetools==4.2.4
certifi==2021.5.30
cffi==1.15.1
chardet==3.0.4
cryptography==40.0.2
decorator==5.1.1
dogpile.cache==1.2.2
DukeDSClient==1.0.3
future==1.0.0
google-auth==2.22.0
humanfriendly==2.4
idna==2.7
importlib-metadata @ file:///tmp/build/80754af9/importlib-metadata_1631916693255/work
iniconfig @ file:///home/linux1/recipes/ci/iniconfig_1610983019677/work
iso8601==1.1.0
Jinja2==2.9.5
jmespath==0.10.0
jsonpatch==1.32
jsonpointer==2.3
keystoneauth1==5.1.3
kubernetes==8.0.1
-e git+https://github.com/Duke-GCB/lando.git@ed29711ca564a5d18bf8752a3e0c09661c1d6fca#egg=lando
lando-messaging==1.0.0
Markdown==2.6.9
MarkupSafe==2.0.1
more-itertools @ file:///tmp/build/80754af9/more-itertools_1637733554872/work
munch==4.0.0
netifaces==0.11.0
nose==1.3.7
oauthlib==3.2.2
openstacksdk==0.49.0
os-client-config==2.1.0
os-service-types==1.7.0
packaging @ file:///tmp/build/80754af9/packaging_1637314298585/work
pbr==6.1.1
pika==0.10.0
pluggy @ file:///tmp/build/80754af9/pluggy_1615976315926/work
py @ file:///opt/conda/conda-bld/py_1644396412707/work
pyasn1==0.4.8
pyasn1-modules==0.3.0
pycparser==2.21
PyJWT==2.4.0
pyparsing @ file:///tmp/build/80754af9/pyparsing_1635766073266/work
pytest==6.2.4
python-dateutil==2.6.0
pytz==2025.2
PyYAML==3.12
requests==2.20.1
requests-oauthlib==2.0.0
requestsexceptions==1.4.0
rsa==4.9
shade==1.29.0
six==1.17.0
stevedore==3.5.2
toml @ file:///tmp/build/80754af9/toml_1616166611790/work
typing_extensions @ file:///opt/conda/conda-bld/typing_extensions_1647553014482/work
urllib3==1.24.3
websocket-client==1.3.1
zipp @ file:///tmp/build/80754af9/zipp_1633618647012/work

name: lando
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - attrs=21.4.0=pyhd3eb1b0_0
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - importlib-metadata=4.8.1=py36h06a4308_0
  - importlib_metadata=4.8.1=hd3eb1b0_0
  - iniconfig=1.1.1=pyhd3eb1b0_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - more-itertools=8.12.0=pyhd3eb1b0_0
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - packaging=21.3=pyhd3eb1b0_0
  - pip=21.2.2=py36h06a4308_0
  - pluggy=0.13.1=py36h06a4308_0
  - py=1.11.0=pyhd3eb1b0_0
  - pyparsing=3.0.4=pyhd3eb1b0_0
  - pytest=6.2.4=py36h06a4308_2
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - toml=0.10.2=pyhd3eb1b0_0
  - typing_extensions=4.1.1=pyh06a4308_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zipp=3.6.0=pyhd3eb1b0_0
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - adal==1.2.7
      - appdirs==1.4.4
      - cachetools==4.2.4
      - cffi==1.15.1
      - chardet==3.0.4
      - cryptography==40.0.2
      - decorator==5.1.1
      - dogpile-cache==1.2.2
      - dukedsclient==1.0.3
      - future==1.0.0
      - google-auth==2.22.0
      - humanfriendly==2.4
      - idna==2.7
      - iso8601==1.1.0
      - jinja2==2.9.5
      - jmespath==0.10.0
      - jsonpatch==1.32
      - jsonpointer==2.3
      - keystoneauth1==5.1.3
      - kubernetes==8.0.1
      - lando-messaging==1.0.0
      - markdown==2.6.9
      - markupsafe==2.0.1
      - munch==4.0.0
      - netifaces==0.11.0
      - nose==1.3.7
      - oauthlib==3.2.2
      - openstacksdk==0.49.0
      - os-client-config==2.1.0
      - os-service-types==1.7.0
      - pbr==6.1.1
      - pika==0.10.0
      - pyasn1==0.4.8
      - pyasn1-modules==0.3.0
      - pycparser==2.21
      - pyjwt==2.4.0
      - python-dateutil==2.6.0
      - pytz==2025.2
      - pyyaml==3.12
      - requests==2.20.1
      - requests-oauthlib==2.0.0
      - requestsexceptions==1.4.0
      - rsa==4.9
      - shade==1.29.0
      - six==1.17.0
      - stevedore==3.5.2
      - urllib3==1.24.3
      - websocket-client==1.3.1
prefix: /opt/conda/envs/lando

lando/worker/tests/test_cwlworkflow.py::TestResultsDirectory::test_add_files
lando/worker/tests/test_cwlworkflow.py::TestCwlWorkflow::test_simple_workflow_succeeds
lando/worker/tests/test_cwlworkflow.py::TestCwlWorkflow::test_post_process_command lando/worker/tests/test_cwlworkflow.py::TestCwlWorkflow::test_simple_workflow_missing_files lando/worker/tests/test_cwlworkflow.py::TestCwlWorkflow::test_workflow_bad_exit_status lando/worker/tests/test_cwlworkflow.py::TestCwlDirectory::test_constructor lando/worker/tests/test_cwlworkflow.py::CwlWorkflowDownloaderTestCase::test_copy_packed lando/worker/tests/test_cwlworkflow.py::CwlWorkflowDownloaderTestCase::test_copy_zipped lando/worker/tests/test_cwlworkflow.py::CwlWorkflowDownloaderTestCase::test_downloads_packed lando/worker/tests/test_cwlworkflow.py::CwlWorkflowDownloaderTestCase::test_downloads_then_raises_on_other_type lando/worker/tests/test_cwlworkflow.py::CwlWorkflowDownloaderTestCase::test_downloads_zipped lando/worker/tests/test_cwlworkflow.py::CwlWorkflowDownloaderActivityPathTestCase::test_get_workflow_activity_path_packed lando/worker/tests/test_cwlworkflow.py::CwlWorkflowDownloaderActivityPathTestCase::test_get_workflow_activity_path_raises_other lando/worker/tests/test_cwlworkflow.py::CwlWorkflowDownloaderActivityPathTestCase::test_get_workflow_activity_path_zipped lando/worker/tests/test_cwlworkflow.py::TestCwlWorkflowProcess::test_run_stderr_bad_exit lando/worker/tests/test_cwlworkflow.py::TestCwlWorkflowProcess::test_run_stdout_good_exit lando/worker/tests/test_cwlworkflow.py::TestResultsDirectory::test_add_files_null_methods_document lando/worker/tests/test_cwlworkflow.py::TestReadFile::test_reads_file_using_codecs lando/worker/tests/test_cwlworkflow.py::TestReadFile::test_returns_empty_string_on_error
lando/worker/cwlworkflow.py
lando/worker/cwlworkflow.py