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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/terraphim_lsp/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/terraphim_lsp/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ resolver = "2"
members = [".", "../terraphim_lsp_core"]

[workspace.package]
version = "1.22.0-rc.5"
version = "1.22.0-rc.6"
edition = "2024"
rust-version = "1.91"

Expand Down
23 changes: 21 additions & 2 deletions docs/plans/public-lsp-packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ change. The original `alternative.add` result remains unchanged.

- `terraphim_lsp_core` is version `1.23.1`, with public dependencies on types
`1.22.3`, automata `2.1.0`, alternatives `0.1.1` and Lab `0.1.1`.
- `terraphim_lsp` is the `1.22.0-rc.5` candidate and depends on core `1.23.1`.
- `terraphim_lsp` is the `1.22.0-rc.6` candidate and depends on core `1.23.1`.
- Both packages restrict publication to crates.io and include the Apache-2.0
licence notice and their own test fixtures. No private Git history, registry
credentials or operational files are part of the snapshot.
Expand Down Expand Up @@ -64,7 +64,7 @@ outside the source checkout. A second job reproduces the qualified archive
before requesting publication credentials.

Core `terraphim_lsp_core-v1.23.1` is already published. The next server tag is
`terraphim_lsp-v1.22.0-rc.5`; the published RC4 crate and source tag remain immutable. Existing crates use the `crates-io` environment and
`terraphim_lsp-v1.22.0-rc.6`; the published RC4/RC5 crates and source tags remain immutable. Existing crates use the `crates-io` environment and
crates.io trusted publishing. A first-ever crate name uses a deliberate manual
run on its exact tag with `auth_mode=bootstrap` and the `crates-io-bootstrap`
environment. This temporary path reads the existing `CARGO_REGISTRY_TOKEN`
Expand Down Expand Up @@ -126,3 +126,22 @@ and synonym-export protocol checks; ARM64 was architecture-checked without a
native runtime claim. These diagnostic outputs are not published release assets.
RC5 changes the server release identity and build helper; core 1.23.1 remains
unchanged. The normal release workflow must qualify and publish the new source.

## Build-log filename correction

RC5 successfully published its crate and built all six binaries. Final assembly
then rejected real log names such as `build-x86_64-unknown-linux-musl.log`: the
validator excluded underscores even though the producer uses target triples in
its filenames. The validator now accepts only the exact `fetch-<target>.log`
and `build-<target>.log` names for each known target, or `universal.log` for the
combined macOS asset. Test fixtures use these actual producer names, and the
full saved RC5 artifact set is reassembled locally as regression evidence.

RC6 uses the established tag/OIDC workflow with this validator correction;
server runtime code and core 1.23.1 remain unchanged. RC5 diagnostic assembly
outputs are not published binaries. The previous crate and tag remain intact.

The current workflow names producer artifacts by run attempt. A failed-publish-
only retry would request a newer attempt's artifacts that were never produced;
such a retry is not a supported recovery route. Do not move a tag, replace
artifacts, or relax protected-environment rules to recover a publication.
2 changes: 1 addition & 1 deletion release/lsp-crates.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
},
{
"name": "terraphim_lsp",
"version": "1.22.0-rc.5",
"version": "1.22.0-rc.6",
"path": "crates/terraphim_lsp/Cargo.toml"
}
]
Expand Down
4 changes: 3 additions & 1 deletion scripts/lsp_public_binary.py
Original file line number Diff line number Diff line change
Expand Up @@ -428,9 +428,11 @@ def bundle(folder, qualification, expected, write=False):
require(protocol == {'status': 'NOT_RUN_CROSS_TARGET'}, 'Unexecuted target has misleading protocol evidence')
commands = record.get('commands')
require(isinstance(commands, list) and commands, 'Missing executed build commands')
allowed_logs = {'universal.log'} if target.startswith('universal') else {
'fetch-' + target + '.log', 'build-' + target + '.log'}
for command_record in commands:
require(isinstance(command_record, dict) and isinstance(command_record.get('log'), str)
and re.fullmatch(r'[a-z0-9-]+\.log', command_record['log']), 'Invalid build log name')
and command_record['log'] in allowed_logs, 'Invalid build log name')
log = folder / 'logs' / target / command_record['log']
require(command_record.get('exitCode') == 0 and log.is_file() and not log.is_symlink()
and publisher.digest(log) == command_record.get('sha256'), 'Build log differs')
Expand Down
35 changes: 31 additions & 4 deletions tests/test_lsp_public_binary.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,17 @@ def fixture_bundle(self):
target=name.removeprefix('terraphim-lsp-');path=folder/name;path.write_bytes(self.executable(target))
for name in b.RAW:
target=name.removeprefix('terraphim-lsp-');path=folder/name;logs=folder/'logs'/target;logs.mkdir(parents=True)
log=logs/'build.log';log.write_text('Fixture build log\n')
log=logs/('universal.log' if target.startswith('universal') else 'build-'+target+'.log');log.write_text('Fixture build log\n')
argv=['rustup','run','1.96','cargo','build','--locked','--offline','--release','--target',target,'--bin','terraphim-lsp']
extra={}
if target.startswith('universal'):
argv=['lipo','-create'];extra={'inputHashes':{n:b.publisher.digest(folder/n) for n in b.RAW if n in ('terraphim-lsp-aarch64-apple-darwin','terraphim-lsp-x86_64-apple-darwin')}}
record={'schema':1,'status':'PASS','source':source,'target':target,'asset':{'name':name,'sha256':b.publisher.digest(path),'bytes':path.stat().st_size},'architectures':b.architecture(path),'host':{'system':'Fixture','machine':'Fixture'},'nativeVersion':{'status':'PASS','exitCode':0,'stdout':'terraphim-lsp 1.22.0-rc.4\n'},'commands':[{'argv':argv,'exitCode':0,'log':log.name,'sha256':b.publisher.digest(log)}],'extra':extra}
build_commands=[]
if not target.startswith('universal'):
fetched=logs/('fetch-'+target+'.log');fetched.write_text('Fixture fetch log\n')
build_commands.append({'argv':['rustup','run','1.96','cargo','fetch','--locked','--target',target],'exitCode':0,'log':fetched.name,'sha256':b.publisher.digest(fetched)})
build_commands.append({'argv':argv,'exitCode':0,'log':log.name,'sha256':b.publisher.digest(log)})
record={'schema':1,'status':'PASS','source':source,'target':target,'asset':{'name':name,'sha256':b.publisher.digest(path),'bytes':path.stat().st_size},'architectures':b.architecture(path),'host':{'system':'Fixture','machine':'Fixture'},'nativeVersion':{'status':'PASS','exitCode':0,'stdout':'terraphim-lsp 1.22.0-rc.4\n'},'commands':build_commands,'extra':extra}
smoke=folder/'smoke'/target;smoke.mkdir(parents=True)
(smoke/'input.md').write_text('Risk: delivery may slip.\n')
(smoke/'brief.md').write_text('Risk: delivery may slip.\nFixture annotation: Concern\n')
Expand Down Expand Up @@ -111,6 +116,18 @@ def test_real_subprocess_log_is_saved_and_hash_bound(self):
b.command([sys.executable,'-c','raise SystemExit(4)'],lane,lane,'real-failure')
self.assertTrue((lane/'logs/real-failure.log').is_file())

def test_actual_producer_log_names_save_real_subprocess_output(self):
lane=self.root/'producer-names';lane.mkdir()
names=['universal', *[step+'-'+target for target in b.TARGETS for step in ('fetch','build')]]
for name in names:
with self.subTest(name=name):
record=b.command([sys.executable,'-c','print("actual producer-name output")'],lane,lane,name)
log=lane/'logs'/(name+'.log')
self.assertEqual(record['log'],name+'.log')
self.assertEqual(log.read_text(),'actual producer-name output\n')
self.assertEqual(record['sha256'],b.publisher.digest(log))
self.assertEqual(record['exitCode'],0)

def test_cross_environment_omits_host_build_dir_without_changing_native(self):
lane = self.root / 'lane'
previous = os.environ.get('CARGO_BUILD_BUILD_DIR')
Expand Down Expand Up @@ -163,14 +180,24 @@ def test_bundle_round_trip_preserves_six_raw_names(self):
self.assertEqual({p.name for p in paths},set(b.publisher.RELEASE_FILES))
self.assertEqual(b.bundle(folder,q,self.expected),paths)

def test_log_names_must_match_the_exact_producer_target(self):
folder,q=self.fixture_bundle();target='x86_64-unknown-linux-musl';p=folder/(target+'.json')
record=json.loads(p.read_text())
self.assertEqual([c['log'] for c in record['commands']],['fetch-'+target+'.log','build-'+target+'.log'])
for name in ['../build-'+target+'.log','build-aarch64-unknown-linux-musl.log','build.log','BUILD-'+target+'.log','build-'+target+'.log/other']:
with self.subTest(name=name):
record['commands'][-1]['log']=name;p.write_text(json.dumps(record))
with self.assertRaisesRegex(ValueError,'Invalid build log name'):
b.bundle(folder,q,self.expected,write=True)

def test_mutated_asset_and_extra_file_refused(self):
folder,q=self.fixture_bundle();b.bundle(folder,q,self.expected,write=True)
(folder/b.RAW[0]).write_bytes(b'changed')
with self.assertRaises(ValueError):b.bundle(folder,q,self.expected)

def test_changed_build_log_and_wrong_target_refused(self):
folder,q=self.fixture_bundle();target=b.RAW[0].removeprefix('terraphim-lsp-')
log=folder/'logs'/target/'build.log';log.write_text('changed')
log=folder/'logs'/target/('build-'+target+'.log');log.write_text('changed')
with self.assertRaisesRegex(ValueError,'Build log'):b.bundle(folder,q,self.expected,write=True)

def test_skipped_native_test_and_changed_source_refused(self):
Expand All @@ -179,7 +206,7 @@ def test_skipped_native_test_and_changed_source_refused(self):

def test_wrong_build_target_is_refused(self):
folder,q=self.fixture_bundle();p=folder/'aarch64-unknown-linux-musl.json';record=json.loads(p.read_text())
record['commands'][0]['argv'][-3]='x86_64-unknown-linux-musl';p.write_text(json.dumps(record))
record['commands'][-1]['argv'][-3]='x86_64-unknown-linux-musl';p.write_text(json.dumps(record))
with self.assertRaisesRegex(ValueError,'Build target'):b.bundle(folder,q,self.expected,write=True)

def test_extra_asset_is_refused(self):
Expand Down
Loading