test(integ): cover the new set options and the export attribute
43 GNU-pinned cases: `assign/export_attr.json`, plus noclobber, noexec, verbose and braceexpand under `setopt/`, which had errexit, noglob, nounset, pipefail and xtrace but none of stage 1. The noexec cases are what caught the subshell bug. Both runners and `state_store` wrote into `ws.env`, which the read-only projection refuses, so the battery could not start on either host. A meta-test now scans for that write shape across both trees: mypy runs on `mirage/` alone, so `integ/` and `tests/` are exactly where it recurs unseen.
This commit is contained in:
@@ -0,0 +1,820 @@
|
||||
{
|
||||
"cases": [
|
||||
{
|
||||
"id": "export_env_carries_only_exported",
|
||||
"seq": 930400,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "QEA=hello; export QEB=world; env | grep -E \"^QE(A|B)=\"",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "QEB=world\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "export_declared_unset_stays_out_of_env",
|
||||
"seq": 930401,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "export QEC; env | grep -c \"^QEC=\"",
|
||||
"expect": {
|
||||
"exit": 1,
|
||||
"stdout": "0\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "export_n_drops_from_env",
|
||||
"seq": 930402,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "export QED=world; export -n QED; env | grep -c \"^QED=\"",
|
||||
"expect": {
|
||||
"exit": 1,
|
||||
"stdout": "0\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "export_allexport_marks_only_while_on",
|
||||
"seq": 930403,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "QEF=1; set -a; QEG=2; set +a; QEH=3; env | grep -cE \"^QE(F|G|H)=\"",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "1\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "declare_p_plain_and_exported",
|
||||
"seq": 930404,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "QEI=hello; export QEJ=world; declare -p QEI QEJ",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "declare -- QEI=\"hello\"\ndeclare -x QEJ=\"world\"\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "declare_p_declared_but_unset",
|
||||
"seq": 930405,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "export QEK; declare -p QEK",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "declare -x QEK\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "declare_x_marks_existing_name",
|
||||
"seq": 930406,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "QEL=val; declare -x QEL; declare -p QEL",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "declare -x QEL=\"val\"\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "export_n_leaves_ordinary_variable",
|
||||
"seq": 930407,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "export QEM=world; export -n QEM; declare -p QEM",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "declare -- QEM=\"world\"\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "declare_p_attribute_order",
|
||||
"seq": 930408,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "export QEN=v; readonly QEN; declare -p QEN",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "declare -rx QEN=\"v\"\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "declare_p_unknown_name_exits_1",
|
||||
"seq": 930409,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "QEO=good; declare -p QEO QENOPE",
|
||||
"expect": {
|
||||
"exit": 1,
|
||||
"stdout": "declare -- QEO=\"good\"\n",
|
||||
"stderr": "bash: declare: QENOPE: not found\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "export_p_lists_exported_only",
|
||||
"seq": 930410,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "QEP=hello; export QEQ=world; export QER; export -p | grep -E \"^declare -x QE(P|Q|R)\"",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "declare -x QEQ=\"world\"\ndeclare -x QER\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "printenv_refuses_a_plain_variable",
|
||||
"seq": 930411,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "QES=plain; printenv QES",
|
||||
"expect": {
|
||||
"exit": 1,
|
||||
"stdout": "",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "printenv_reads_an_exported_one",
|
||||
"seq": 930412,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "export QET=e; printenv QET",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "e\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "plain_variable_still_expands",
|
||||
"seq": 930413,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "QEU=hello; echo $QEU",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "hello\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "cd_exports_pwd_and_oldpwd",
|
||||
"seq": 930414,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "cd /; mkdir -p /data/qed; cd /data/qed; cd /data; declare -p PWD OLDPWD",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "declare -x PWD=\"/data\"\ndeclare -x OLDPWD=\"/data/qed\"\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "export_refuses_invalid_identifier",
|
||||
"seq": 930415,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "export 1QEBAD=x",
|
||||
"expect": {
|
||||
"exit": 1,
|
||||
"stdout": "",
|
||||
"stderr": "bash: export: `1QEBAD=x': not a valid identifier\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "readonly_refuses_invalid_identifier",
|
||||
"seq": 930416,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "readonly 2QEBAD=y",
|
||||
"expect": {
|
||||
"exit": 1,
|
||||
"stdout": "",
|
||||
"stderr": "bash: readonly: `2QEBAD=y': not a valid identifier\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "local_refuses_invalid_identifier",
|
||||
"seq": 930417,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "qe_fn() { local 3QEBAD=z; }; qe_fn",
|
||||
"expect": {
|
||||
"exit": 1,
|
||||
"stdout": "",
|
||||
"stderr": "bash: local: `3QEBAD=z': not a valid identifier\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "declare_refuses_invalid_identifier",
|
||||
"seq": 930418,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "declare 4QEBAD=w",
|
||||
"expect": {
|
||||
"exit": 1,
|
||||
"stdout": "",
|
||||
"stderr": "bash: declare: `4QEBAD=w': not a valid identifier\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "export_bare_refuses_invalid_identifier",
|
||||
"seq": 930419,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "export 5QEBAD",
|
||||
"expect": {
|
||||
"exit": 1,
|
||||
"stdout": "",
|
||||
"stderr": "bash: export: `5QEBAD': not a valid identifier\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "export_refuses_subscript_target",
|
||||
"seq": 930420,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "export qearr[0]=1",
|
||||
"expect": {
|
||||
"exit": 1,
|
||||
"stdout": "",
|
||||
"stderr": "bash: export: `qearr[0]': not a valid identifier\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "export_reports_each_bad_operand",
|
||||
"seq": 930421,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "export 6QEBAD=x 7QEBAD=y",
|
||||
"expect": {
|
||||
"exit": 1,
|
||||
"stdout": "",
|
||||
"stderr": "bash: export: `6QEBAD=x': not a valid identifier\nbash: export: `7QEBAD=y': not a valid identifier\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "export_keeps_good_names_on_a_bad_line",
|
||||
"seq": 930422,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "export QEV=1 8QEBAD=x QEW=2; declare -p QEV QEW",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "declare -x QEV=\"1\"\ndeclare -x QEW=\"2\"\n",
|
||||
"stderr": "bash: export: `8QEBAD=x': not a valid identifier\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "export_quoted_empty_operand_is_refused",
|
||||
"seq": 930423,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "export \"\"",
|
||||
"expect": {
|
||||
"exit": 1,
|
||||
"stdout": "",
|
||||
"stderr": "bash: export: `': not a valid identifier\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
{
|
||||
"cases": [
|
||||
{
|
||||
"id": "opt_braceexpand_on_by_default",
|
||||
"seq": 502813,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "echo {a,b}",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "a b\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "opt_braceexpand_plus_b_keeps_literal",
|
||||
"seq": 502814,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "(set +B; echo {a,b})",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "{a,b}\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "opt_braceexpand_listed_off_under_plus_b",
|
||||
"seq": 502815,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "(set +B; set -o | grep braceexpand)",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "braceexpand \toff\n",
|
||||
"stderr": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
{
|
||||
"cases": [
|
||||
{
|
||||
"id": "opt_noclobber_refuses_overwrite",
|
||||
"seq": 502800,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "echo a > /data/zqs1.txt; (set -C; echo b > /data/zqs1.txt); echo rc=$?; cat /data/zqs1.txt",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "rc=1\na\n",
|
||||
"stderr": "/data/zqs1.txt: cannot overwrite existing file\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "opt_noclobber_pipe_override_writes",
|
||||
"seq": 502801,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "echo a > /data/zqs2.txt; (set -C; echo b >| /data/zqs2.txt); echo rc=$?; cat /data/zqs2.txt",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "rc=0\nb\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "opt_noclobber_append_allowed",
|
||||
"seq": 502802,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "echo a > /data/zqs3.txt; (set -C; echo b >> /data/zqs3.txt); echo rc=$?; cat /data/zqs3.txt",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "rc=0\na\nb\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "opt_noclobber_new_target_allowed",
|
||||
"seq": 502803,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "(set -C; echo n > /data/zqs4.txt); echo rc=$?; cat /data/zqs4.txt",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "rc=0\nn\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "opt_noclobber_long_name_same_option",
|
||||
"seq": 502804,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "echo a > /data/zqs5.txt; (set -o noclobber; echo b > /data/zqs5.txt); echo rc=$?",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "rc=1\n",
|
||||
"stderr": "/data/zqs5.txt: cannot overwrite existing file\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "opt_noclobber_directory_wording",
|
||||
"seq": 502805,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "mkdir -p /data/zqsd; (set -C; echo b > /data/zqsd); echo rc=$?",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "rc=1\n",
|
||||
"stderr": "/data/zqsd: Is a directory\n"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "opt_noclobber_off_by_default",
|
||||
"seq": 502806,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "echo a > /data/zqs6.txt; echo b > /data/zqs6.txt; echo rc=$?; cat /data/zqs6.txt",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "rc=0\nb\n",
|
||||
"stderr": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
{
|
||||
"cases": [
|
||||
{
|
||||
"id": "opt_noexec_skips_rest_of_subshell",
|
||||
"seq": 502807,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "(set -n; echo hi); echo rc=$?",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "rc=0\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "opt_noexec_only_inside_the_subshell",
|
||||
"seq": 502808,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "echo a; (set -n; echo b); echo c",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "a\nc\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "opt_noexec_plus_n_never_runs",
|
||||
"seq": 502809,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "(set -n; set +n; echo after); echo rc=$?",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "rc=0\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "opt_noexec_does_not_leak_out",
|
||||
"seq": 502810,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "(set -n; echo x); echo still-here",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "still-here\n",
|
||||
"stderr": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -101,6 +101,74 @@
|
||||
"stdout": "1\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "opt_set_o_lists_option_state",
|
||||
"seq": 502816,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "set -o | grep noclobber",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "noclobber \toff\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "opt_set_plus_o_is_re_readable",
|
||||
"seq": 502817,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "set +o | grep -c '^set [-+]o noclobber$'",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "1\n",
|
||||
"stderr": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
{
|
||||
"cases": [
|
||||
{
|
||||
"id": "opt_verbose_same_line_echoes_nothing",
|
||||
"seq": 502812,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "(set -v; echo hi)",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "hi\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "opt_verbose_subshell_read_as_one_unit",
|
||||
"seq": 502813,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "(set -v\necho hi)",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "hi\n",
|
||||
"stderr": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "opt_verbose_echoes_lines_read_while_on",
|
||||
"seq": 502814,
|
||||
"targets": [
|
||||
"ram",
|
||||
"disk",
|
||||
"redis",
|
||||
"opfs",
|
||||
"s3",
|
||||
"databricks",
|
||||
"gridfs",
|
||||
"s3-prefix",
|
||||
"databricks-prefix",
|
||||
"gridfs-prefix",
|
||||
"hf",
|
||||
"hf-prefix",
|
||||
"dropbox",
|
||||
"dropbox-root",
|
||||
"onedrive",
|
||||
"sharepoint",
|
||||
"sharepoint-prefix",
|
||||
"ssh",
|
||||
"nextcloud",
|
||||
"gdrive",
|
||||
"gdrive-folder",
|
||||
"box"
|
||||
],
|
||||
"command": "set -v\necho hi\nset +v\necho after",
|
||||
"expect": {
|
||||
"exit": 0,
|
||||
"stdout": "hi\nafter\n",
|
||||
"stderr": "echo hi\nset +v\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -2293,7 +2293,11 @@ async def open_target(
|
||||
# (ntn's --notion-version off NOTION_API_VERSION) behaves differently
|
||||
# with and without it, so the conformance runner passes the same map
|
||||
# to the real binary and the comparison stays like for like.
|
||||
ws.env.update(target.get("env", {}))
|
||||
# Through the setter, not into the mapping: `ws.env` is a read-only
|
||||
# projection of the variable records, and a target's declared
|
||||
# environment is exported by definition -- a CLI reads it as a
|
||||
# process environment, which carries exported names only.
|
||||
ws.env = {**ws.env, **target.get("env", {})}
|
||||
return ws, functools.partial(teardown_target, [ws], cleanups, service)
|
||||
|
||||
|
||||
@@ -2316,8 +2320,8 @@ async def open_consistency(
|
||||
# Same rule as open_target: a target's declared environment reaches
|
||||
# every workspace a case can run against, or a consistency scenario
|
||||
# would silently run under a different one.
|
||||
read_ws.env.update(target.get("env", {}))
|
||||
shadow_ws.env.update(target.get("env", {}))
|
||||
read_ws.env = {**read_ws.env, **target.get("env", {})}
|
||||
shadow_ws.env = {**shadow_ws.env, **target.get("env", {})}
|
||||
return (
|
||||
read_ws,
|
||||
functools.partial(mutate_write, shadow_ws),
|
||||
|
||||
@@ -85,7 +85,11 @@ async function runTarget(
|
||||
// (ntn's --notion-version off NOTION_API_VERSION) behaves differently with
|
||||
// and without it, so the conformance runner passes the same map to the real
|
||||
// binary and the comparison stays like for like.
|
||||
Object.assign(ws.env, target.env ?? {})
|
||||
// Through the setter, not into the record: `ws.env` is a frozen
|
||||
// projection of the variable records, and a target's declared
|
||||
// environment is exported by definition -- a CLI reads it as a
|
||||
// process environment, which carries exported names only.
|
||||
ws.env = { ...ws.env, ...(target.env ?? {}) }
|
||||
for (const mount of target.mounts) {
|
||||
await seedFixture(ws, mount.fixture, mount.path, root)
|
||||
if (mount.seed_root) await seedMountRoot(ws, mount.path)
|
||||
@@ -166,7 +170,7 @@ async function runTarget(
|
||||
// Same rule as the ordinary path: a target's declared environment reaches
|
||||
// every workspace a case can run against, or a consistency scenario would
|
||||
// silently run under a different one.
|
||||
Object.assign(opened.ws.env, target.env ?? {})
|
||||
opened.ws.env = { ...opened.ws.env, ...(target.env ?? {}) }
|
||||
const { exitCode, out } = await runScenario(opened.ws, opened.mutate, c.scenario)
|
||||
if (emit !== null) {
|
||||
emit.push({ target: target.id, id: c.id, exit: exitCode, stdout: out, stderr: '' })
|
||||
|
||||
@@ -24,6 +24,7 @@ import uuid # noqa: E402
|
||||
from mirage import MountMode, Workspace # noqa: E402
|
||||
from mirage.accessor.s3 import S3Config # noqa: E402
|
||||
from mirage.resource.ram import RAMResource # noqa: E402
|
||||
from mirage.workspace.session.state import seed_var # noqa: E402
|
||||
from mirage.workspace.session.store import SessionStore # noqa: E402
|
||||
from mirage.workspace.store.redis import RedisWorkspaceStateStore # noqa: E402
|
||||
from mirage.workspace.store.s3 import S3WorkspaceStateStore # noqa: E402
|
||||
@@ -89,7 +90,7 @@ async def write(prefix: str) -> None:
|
||||
check("py write: symlink", result.exit_code == 0)
|
||||
ws.create_session("narrow", mounts={"/data": "read"})
|
||||
shared = ws.create_session("shared")
|
||||
shared.env["ORIGIN"] = "py"
|
||||
seed_var(shared, "ORIGIN", "py")
|
||||
await ws.flush_sessions()
|
||||
check("py write: shared session at generation 1", shared.generation == 1,
|
||||
f"got {shared.generation}")
|
||||
@@ -141,7 +142,7 @@ async def read(prefix: str) -> None:
|
||||
check("py read: shared session hydrated",
|
||||
shared.env.get("ORIGIN") == "ts" and base >= 1,
|
||||
f"got env={shared.env!r} generation={base}")
|
||||
shared.env["REPLY"] = "py"
|
||||
seed_var(shared, "REPLY", "py")
|
||||
await ws.flush_sessions()
|
||||
sess_store = store.sessions(WORKSPACE_ID)
|
||||
entries = await sess_store.load()
|
||||
@@ -156,7 +157,7 @@ async def read(prefix: str) -> None:
|
||||
ahead = dict(entries["shared"])
|
||||
ahead["generation"] = base + 5
|
||||
await sess_store.set("shared", ahead)
|
||||
shared.env["AGAIN"] = "py"
|
||||
seed_var(shared, "AGAIN", "py")
|
||||
await ws.flush_sessions()
|
||||
entries = await sess_store.load()
|
||||
check(
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
import { MountMode, RAMResource, type SessionStore } from '@struktoai/mirage-core'
|
||||
import { seedVar } from '@struktoai/mirage-core/workspace/session/state'
|
||||
import { RedisWorkspaceStateStore, S3WorkspaceStateStore, Workspace } from '@struktoai/mirage-node'
|
||||
|
||||
const REDIS_URL = process.env.REDIS_URL ?? 'redis://localhost:6379/0'
|
||||
@@ -74,7 +75,7 @@ async function write(prefix: string): Promise<void> {
|
||||
check('ts write: symlink', link.exitCode === 0)
|
||||
ws.createSession('narrow', { mounts: { '/data': 'read' } })
|
||||
const shared = ws.createSession('shared')
|
||||
shared.env.ORIGIN = 'ts'
|
||||
seedVar(shared, 'ORIGIN', 'ts')
|
||||
await ws.flushSessions()
|
||||
check(
|
||||
'ts write: shared session at generation 1',
|
||||
@@ -139,7 +140,7 @@ async function read(prefix: string): Promise<void> {
|
||||
shared.env.ORIGIN === 'py' && base >= 1,
|
||||
`got env=${JSON.stringify(shared.env)} generation=${String(base)}`,
|
||||
)
|
||||
shared.env.REPLY = 'ts'
|
||||
seedVar(shared, 'REPLY', 'ts')
|
||||
await ws.flushSessions()
|
||||
const sessStore = store.sessions(WORKSPACE_ID)
|
||||
const bumped = (await sessStore.load()).get('shared')
|
||||
@@ -155,7 +156,7 @@ async function read(prefix: string): Promise<void> {
|
||||
// A third writer advances the record behind our back; the next flush
|
||||
// must adopt its generation and land serialized on top.
|
||||
await sessStore.set('shared', { ...(bumped ?? {}), generation: base + 5 })
|
||||
shared.env.AGAIN = 'ts'
|
||||
seedVar(shared, 'AGAIN', 'ts')
|
||||
await ws.flushSessions()
|
||||
const final = (await sessStore.load()).get('shared')
|
||||
const finalEnv = (final?.env ?? {}) as Record<string, string>
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ========= Copyright 2026 @ Strukto.AI All Rights Reserved. =========
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parents[4]
|
||||
|
||||
# `Session.env` / `.arrays` / `.readonly_vars` are read-only projections
|
||||
# of the variable records (MappingProxyType in python, Object.freeze in
|
||||
# TypeScript), so a write into one raises at runtime rather than landing.
|
||||
# Writers go through `seed_var`/`seedVar`, `set_attr`/`setAttr`, or the
|
||||
# `env` setter, which is what makes the pre_session gate unskippable.
|
||||
#
|
||||
# This is a meta-test rather than a type rule because the code that keeps
|
||||
# getting it wrong is exactly the code no type checker sees: mypy runs on
|
||||
# `mirage/` alone (`packages = ["mirage"]` in pyproject, and the hook is
|
||||
# gated on `^python/mirage/`), so `integ/` and `tests/` are invisible to
|
||||
# it, and that is where all of the last batch lived -- two runners and
|
||||
# three state_store writes, none of which ran often enough to be caught
|
||||
# by their own exception.
|
||||
PY_PATTERNS = (
|
||||
re.compile(r"\.env\.(update|pop|setdefault|clear)\s*\("),
|
||||
re.compile(r"\.env\[[^\]]+\]\s*=[^=]"),
|
||||
re.compile(r"\.arrays\.(update|pop|setdefault|clear)\s*\("),
|
||||
re.compile(r"\.arrays\[[^\]]+\]\s*=[^=]"),
|
||||
)
|
||||
TS_PATTERNS = (
|
||||
re.compile(r"Object\.assign\(\s*[A-Za-z_][\w.]*\.(env|arrays)\b"),
|
||||
re.compile(r"(?<!process)\.env\.[A-Za-z_]\w*\s*=[^=]"),
|
||||
re.compile(r"(?<!process)\.env\[[^\]]+\]\s*=[^=]"),
|
||||
)
|
||||
|
||||
# `CommandOpts.env` is a plain dict copy handed to one command
|
||||
# invocation (`env_snapshot` returns a fresh dict), so writing into it is
|
||||
# writing into a throwaway and is exactly what these two tests assert.
|
||||
ALLOWED = {
|
||||
"python/tests/workspace/test_state_doors.py",
|
||||
"typescript/packages/core/src/workspace/state_doors.test.ts",
|
||||
}
|
||||
|
||||
SEARCH_ROOTS = ("python/mirage", "python/tests", "integ", "examples",
|
||||
"typescript/packages")
|
||||
|
||||
|
||||
def _sources() -> list[Path]:
|
||||
out: list[Path] = []
|
||||
for root in SEARCH_ROOTS:
|
||||
base = REPO / root
|
||||
if not base.is_dir():
|
||||
continue
|
||||
for path in base.rglob("*"):
|
||||
if path.suffix not in (".py", ".ts"):
|
||||
continue
|
||||
parts = set(path.parts)
|
||||
if parts & {"node_modules", "dist", ".venv", "__pycache__"}:
|
||||
continue
|
||||
out.append(path)
|
||||
return out
|
||||
|
||||
|
||||
def test_no_writes_into_the_read_only_projections() -> None:
|
||||
offenders: list[str] = []
|
||||
for path in _sources():
|
||||
rel = path.relative_to(REPO).as_posix()
|
||||
if rel in ALLOWED:
|
||||
continue
|
||||
patterns = PY_PATTERNS if path.suffix == ".py" else TS_PATTERNS
|
||||
for i, line in enumerate(path.read_text().splitlines(), 1):
|
||||
if any(p.search(line) for p in patterns):
|
||||
offenders.append(f"{rel}:{i}: {line.strip()}")
|
||||
assert not offenders, ("write into a read-only session projection; use "
|
||||
"seed_var/seedVar, set_attr/setAttr or the `env` "
|
||||
"setter instead:\n" + "\n".join(offenders))
|
||||
Reference in New Issue
Block a user